[PATCH i-g-t 1/3] lib/{igt_sysfs, igt_aux}: Make available to other users kick_fbcon() (unbind_fbcon()), and added helpers to igt_aux.

Marius Vlad
2016-10-20T19:30:40Z

Previously under unbind_fbcon(), disable/enable framebuffer console.

lib/igt_aux: Added helpers to help convert sh scripts to C version. libkmod and
procps interface.

Signed-off-by: Marius Vlad <marius.c.vlad@intel.com>
---
configure.ac | 2 +
lib/Makefile.am | 2 +
lib/igt_aux.c | 278 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
lib/igt_aux.h | 7 ++
lib/igt_gvt.c | 43 +--------
lib/igt_sysfs.c | 54 +++++++++++
lib/igt_sysfs.h | 2 +
7 files changed, 347 insertions(+), 41 deletions(-)

diff --git a/configure.ac b/configure.ac
index 735cfd5..2c6e49d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -121,6 +121,8 @@ AC_SUBST(ASSEMBLER_WARN_CFLAGS)

PKG_CHECK_MODULES(DRM, [libdrm])
PKG_CHECK_MODULES(PCIACCESS, [pciaccess >= 0.10])
+PKG_CHECK_MODULES(KMOD, [libkmod])
+PKG_CHECK_MODULES(PROCPS, [libprocps])

case "$target_cpu" in
x86*|i?86)
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 4c0893d..e1737bd 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -34,6 +34,8 @@ AM_CFLAGS += $(CAIRO_CFLAGS)
libintel_tools_la_LIBADD = \
$(DRM_LIBS) \
$(PCIACCESS_LIBS) \
+ $(PROCPS_LIBS) \
+ $(KMOD_LIBS) \
$(CAIRO_LIBS) \
$(LIBUDEV_LIBS) \
$(LIBUNWIND_LIBS) \
diff --git a/lib/igt_aux.c b/lib/igt_aux.c
index 421f6d4..d150818 100644
--- a/lib/igt_aux.c
+++ b/lib/igt_aux.c
@@ -51,6 +51,9 @@
#include <termios.h>
#include <assert.h>

+#include <proc/readproc.h>
+#include <libkmod.h>
+
#include "drmtest.h"
#include "i915_drm.h"
#include "intel_chipset.h"
@@ -1193,6 +1196,281 @@ void igt_set_module_param_int(const char *name, int val)
igt_set_module_param(name, str);
}

+/**
+ * igt_pkill:
+ * @sig: Signal to send
+ * @name: Name of process in the form found in /proc/pid/comm (limited to 15
+ * chars)
+ * @returns: 0 in case the process is not found running or the signal has been
+ * sent successfully or -1 otherwise.
+ *
+ * This function sends the signal @sig for a process found in process table
+ * with name @comm.
+ */
+int
+igt_pkill(int sig, const char *comm)
+{
+ int err = 0, try = 5;
+ PROCTAB *proc;
+ proc_t *proc_info;
+
+ proc = openproc(PROC_FILLCOM | PROC_FILLSTAT | PROC_FILLARG);
+ igt_assert(proc != NULL);
+
+ while ((proc_info = readproc(proc, NULL))) {
+ if (proc_info &&
+ !strncasecmp(proc_info->cmd, comm, sizeof(proc_info->cmd))) {
+ switch (sig) {
+ case SIGTERM:
+ case SIGKILL:
+ do {
+ kill(proc_info->tid, sig);
+ } while (kill(proc_info->tid, 0) < 0 && try--);
+
+ if (kill(proc_info->tid, 0) < 0)
+ err = -1;
+ break;
+ default:
+ if (kill(proc_info->tid, sig) < 0)
+ err = -1;
+ break;
+ }
+
+ freeproc(proc_info);
+ break;
+ }
+ freeproc(proc_info);
+ }
+
+ closeproc(proc);
+ return err;
+}
+
+/**
+ * igt_kill:
+ * @sig: Signal to send.
+ * @pid: Process pid to send.
+ * @returns: 0 in case of success or -1 otherwise.
+ *
+ * This function is identical to igt_pkill() only that it searches the process
+ * table using @pid instead of comm name.
+ *
+ */
+int
+igt_kill(int sig, pid_t pid)
+{
+ int err = 0, try = 5;
+ PROCTAB *proc;
+ proc_t *proc_info;
+
+ proc = openproc(PROC_PID | PROC_FILLSTAT | PROC_FILLARG);
+ igt_assert(proc != NULL);
+
+ while ((proc_info = readproc(proc, NULL))) {
+ if (proc_info && proc_info->tid == pid) {
+ switch (sig) {
+ case SIGTERM:
+ case SIGKILL:
+ do {
+ kill(proc_info->tid, sig);
+ } while (kill(proc_info->tid, 0) < 0 && try--);
+
+ if (kill(proc_info->tid, 0) < 0)
+ err = -1;
+ break;
+ default:
+ if (kill(proc_info->tid, sig) < 0)
+ err = -1;
+ break;
+ }
+ freeproc(proc_info);
+ break;
+ }
+ freeproc(proc_info);
+ }
+
+ closeproc(proc);
+ return err;
+}
+
+static bool
+igt_module_in_use(struct kmod_module *kmod)
+{
+ int err;
+
+ err = kmod_module_get_initstate(kmod);
+
+ /* if compiled builtin or does not exist */
+ if (err == KMOD_MODULE_BUILTIN || err < 0)
+ return false;
+
+ if (kmod_module_get_refcnt(kmod) != 0 ||
+ kmod_module_get_holders(kmod) != NULL)
+ return true;
+
+
+ return false;
+}
+
+/**
+ * igt_lsmod:
+ * @mod_name: The name of the module.
+ * @returns: True in case the module has been found or false otherwise.
+ *
+ *
+ * Function to check the existance of module @mod_name in list of loaded kernel
+ * modules.
+ *
+ */
+bool
+igt_lsmod_has_module(const char *mod_name)
+{
+ struct kmod_list *mod, *list;
+ struct kmod_ctx *ctx;
+ bool ret = false;
+
+ ctx = kmod_new(NULL, NULL);
+ igt_assert(ctx != NULL);
+
+ if (kmod_module_new_from_loaded(ctx, &list) < 0) {
+ kmod_unref(ctx);
+ return ret;
+ }
+
+ kmod_list_foreach(mod, list) {
+ struct kmod_module *kmod = kmod_module_get_module(mod);
+ const char *kmod_name = kmod_module_get_name(kmod);
+
+ if (!strncasecmp(kmod_name, mod_name, strlen(kmod_name))) {
+ kmod_module_unref(kmod);
+ ret = true;
+ break;
+ }
+ kmod_module_unref(kmod);
+ }
+
+ kmod_module_unref_list(list);
+ kmod_unref(ctx);
+
+ return ret;
+}
+
+
+/**
+ * igt_insmod:
+ * @mod_name: The name of the module
+ * @opts: Parameters for the module. NULL in case no parameters
+ * are to be passed, or a '\0' terminated string otherwise.
+ * @returns: 0 in case of success or -1 in case the module could not
+ * be loaded.
+ *
+ *
+ * This function loads a kernel module using the name specified in @mod_name.
+ *
+ * @Note: This functions doesn't automatically resolve other module
+ * dependencies so make make sure you load the dependencies module(s) before
+ * this one.
+ */
+int
+igt_insmod(const char *mod_name, const char *opts)
+{
+ struct kmod_ctx *ctx;
+ struct kmod_module *kmod;
+ int err = 0;
+
+ ctx = kmod_new(NULL, NULL);
+ igt_assert(ctx != NULL);
+
+
+ err = kmod_module_new_from_name(ctx, mod_name, &kmod);
+ if (err < 0) {
+ goto out;
+ }
+
+ err = kmod_module_insert_module(kmod, 0, opts);
+ if (err < 0) {
+ switch (err) {
+ case -EEXIST:
+ igt_info("Module %s already inserted\n",
+ kmod_module_get_name(kmod));
+ err = -1;
+ break;
+ case -ENOENT:
+ igt_info("Unknown symbol in module %s or "
+ "unknown parameter\n",
+ kmod_module_get_name(kmod));
+ err = -1;
+ break;
+ default:
+ igt_info("Could not insert %s (%s)\n",
+ kmod_module_get_name(kmod), strerror(-err));
+ err = -1;
+ break;
+ }
+ }
+out:
+ kmod_module_unref(kmod);
+ kmod_unref(ctx);
+
+ return err;
+}
+
+
+/**
+ * igt_rmmod:
+ * @mod_name: Module name.
+ * @force: A bool value to force removal. Note that his flag does not remove
+ * the module(s) that the module specified by @mod_name depends on. In other
+ * words you must igt_rmmod() the module(s) dependencies before calling it with
+ * @mod_name.
+ * @returns: 0 in case of success or -1 otherwise.
+ *
+ * Removes the module @mod_name.
+ *
+ */
+int
+igt_rmmod(const char *mod_name, bool force)
+{
+ struct kmod_ctx *ctx;
+ struct kmod_module *kmod;
+ int err, flags = 0;
+
+ ctx = kmod_new(NULL, NULL);
+ igt_assert(ctx != NULL);
+
+ err = kmod_module_new_from_name(ctx, mod_name, &kmod);
+ if (err < 0) {
+ igt_info("Could not use module %s (%s)\n", mod_name,
+ strerror(-err));
+ err = -1;
+ goto out;
+ }
+
+ if (igt_module_in_use(kmod)) {
+ igt_info("Module %s is in use\n", mod_name);
+ err = -1;
+ goto out;
+ }
+
+ if (force) {
+ flags |= KMOD_REMOVE_FORCE;
+ }
+
+ err = kmod_module_remove_module(kmod, flags);
+ if (err < 0) {
+ igt_info("Could not remove module %s (%s)\n", mod_name,
+ strerror(-err));
+ err = -1;
+ }
+
+out:
+ kmod_module_unref(kmod);
+ kmod_unref(ctx);
+
+ return err;
+}
+
+
static struct igt_siglatency {
timer_t timer;
struct timespec target;
diff --git a/lib/igt_aux.h b/lib/igt_aux.h
index d30196b..7946923 100644
--- a/lib/igt_aux.h
+++ b/lib/igt_aux.h
@@ -264,4 +264,11 @@ double igt_stop_siglatency(struct igt_mean *result);
void igt_set_module_param(const char *name, const char *val);
void igt_set_module_param_int(const char *name, int val);

+int igt_pkill(int sig, const char *comm);
+int igt_kill(int sig, pid_t pid);
+
+bool igt_lsmod_has_module(const char *mod_name);
+int igt_insmod(const char *mod_name, const char *opts);
+int igt_rmmod(const char *mod_name, bool force);
+
#endif /* IGT_AUX_H */
diff --git a/lib/igt_gvt.c b/lib/igt_gvt.c
index 0f332d1..8bbf9bd 100644
--- a/lib/igt_gvt.c
+++ b/lib/igt_gvt.c
@@ -23,6 +23,7 @@

#include "igt.h"
#include "igt_gvt.h"
+#include "igt_sysfs.h"

#include <dirent.h>
#include <unistd.h>
@@ -46,49 +47,9 @@ static bool is_gvt_enabled(void)
return enabled;
}

-static void unbind_fbcon(void)
-{
- char buf[128];
- const char *path = "/sys/class/vtconsole";
- DIR *dir;
- struct dirent *vtcon;
-
- dir = opendir(path);
- if (!dir)
- return;
-
- while ((vtcon = readdir(dir))) {
- int fd, len;
-
- if (strncmp(vtcon->d_name, "vtcon", 5))
- continue;
-
- sprintf(buf, "%s/%s/name", path, vtcon->d_name);
- fd = open(buf, O_RDONLY);
- if (fd < 0)
- continue;
-
- len = read(fd, buf, sizeof(buf) - 1);
- close(fd);
- if (len >= 0)
- buf[len] = '\0';
-
- if (strstr(buf, "frame buffer device")) {
- sprintf(buf, "%s/%s/bind", path, vtcon->d_name);
- fd = open(buf, O_WRONLY);
- if (fd != -1) {
- igt_ignore_warn(write(fd, "1\n", 2));
- close(fd);
- }
- break;
- }
- }
- closedir(dir);
-}
-
static void unload_i915(void)
{
- unbind_fbcon();
+ kick_fbcon(false);
/* pkill alsact */

igt_ignore_warn(system("/sbin/modprobe -s -r i915"));
diff --git a/lib/igt_sysfs.c b/lib/igt_sysfs.c
index 612de75..0803659 100644
--- a/lib/igt_sysfs.c
+++ b/lib/igt_sysfs.c
@@ -34,7 +34,11 @@
#include <fcntl.h>
#include <unistd.h>
#include <i915_drm.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <fcntl.h>

+#include "igt_core.h"
#include "igt_sysfs.h"

/**
@@ -391,3 +395,53 @@ bool igt_sysfs_set_boolean(int dir, const char *attr, bool value)
{
return igt_sysfs_printf(dir, attr, "%d", value) == 1;
}
+
+/**
+ * kick_fbcon:
+ * @enable: boolean value
+ *
+ * This functions enables/disables the text console running on top of the
+ * framebuffer device.
+ */
+void kick_fbcon(bool enable)
+{
+ char buf[128];
+ const char *path = "/sys/class/vtconsole";
+ DIR *dir;
+ struct dirent *vtcon;
+
+ dir = opendir(path);
+ if (!dir)
+ return;
+
+ while ((vtcon = readdir(dir))) {
+ int fd, len;
+
+ if (strncmp(vtcon->d_name, "vtcon", 5))
+ continue;
+
+ sprintf(buf, "%s/%s/name", path, vtcon->d_name);
+ fd = open(buf, O_RDONLY);
+ if (fd < 0)
+ continue;
+
+ len = read(fd, buf, sizeof(buf) - 1);
+ close(fd);
+ if (len >= 0)
+ buf[len] = '\0';
+
+ if (strstr(buf, "frame buffer device")) {
+ sprintf(buf, "%s/%s/bind", path, vtcon->d_name);
+ fd = open(buf, O_WRONLY);
+ if (fd != -1) {
+ if (enable)
+ igt_ignore_warn(write(fd, "1\n", 2));
+ else
+ igt_ignore_warn(write(fd, "0\n", 2));
+ close(fd);
+ }
+ break;
+ }
+ }
+ closedir(dir);
+}
diff --git a/lib/igt_sysfs.h b/lib/igt_sysfs.h
index 4820066..a141894 100644
--- a/lib/igt_sysfs.h
+++ b/lib/igt_sysfs.h
@@ -43,4 +43,6 @@ bool igt_sysfs_set_u32(int dir, const char *attr, uint32_t value);
bool igt_sysfs_get_boolean(int dir, const char *attr);
bool igt_sysfs_set_boolean(int dir, const char *attr, bool value);

+void kick_fbcon(bool enable);
+
#endif /* __IGT_SYSFS_H__ */
--
2.7.4