summaryrefslogtreecommitdiff
path: root/lib/igt_aux.c
diff options
context:
space:
mode:
authorMarius Vlad <marius.c.vlad@intel.com>2016-12-01 21:45:47 +0000
committerChris Wilson <chris@chris-wilson.co.uk>2016-12-01 21:45:47 +0000
commit0268d73b0b267c6f5acdd4bf40ae917b3afff96c (patch)
treecc5f3c23378db20553bb2087cf5c7f0b1fe1cd49 /lib/igt_aux.c
parent4d8f3b2c8034f1bdf64d65d484e5d5cd18410fb7 (diff)
lib/igt_kmod: New library to support driver loading/unloading and additional helpers.
lib/igt_aux: Added igt_pkill and igt_lsof helper. lib/igt_kmod: Added load/unload kmod helpers. v7: - document the case where leaving stray fd from drm_open_driver() might fail reloading the driver. - list also current opened files from /dev/dri in case we could not unload the driver. - convert igt_info to igt_warn (Chris Wilson) - added KMOD_|PROCPS CFLAGS (Chris Wilson) v6: - include latest modifications from tests/drv_module_reload: display all loaded modules and list information about opened files by processes (Petri Latvala) v5: - added igt_i915_driver_{load/unload}. - added kick_snd_hda_intel() to match current tests/drv_module_reload_basic and integrated into igt_i915_driver_load/unload. - added gtk-doc section for lib/igt_kmod v4: - decided to split libkmod helpers into their own file as there's another user lib/igt_gvt or tests/gvt_basic. - fixed some gtk-doc documentation. v3: - return -errno (igt_pkill()) in case of failure (Cris Wilson) - return bool for igt_kmod_is_loaded(), replaced strncasecmp with strncmp (Chris Wilson) v2: - Renamed libkmod helpers (Chris Wilson) - Removed SIGTERM/SIGKILL case where we repeatedly tried to terminate the process: just call kill(2) once (Chris Wilson) - Removed redundant check in igt_kmod_unload(), igt_module_in_use() (Chris Wilson) - Pass flags to igt_kmod_unload() from the caller (Chris Wilson) - Removed useless function igt_kill() which acts just as kill(2) (Chris Wilson) Signed-off-by: Marius Vlad <marius.c.vlad@intel.com>
Diffstat (limited to 'lib/igt_aux.c')
-rw-r--r--lib/igt_aux.c257
1 files changed, 257 insertions, 0 deletions
diff --git a/lib/igt_aux.c b/lib/igt_aux.c
index b5ae8543..7d5aa52c 100644
--- a/lib/igt_aux.c
+++ b/lib/igt_aux.c
@@ -51,6 +51,8 @@
#include <termios.h>
#include <assert.h>
+#include <proc/readproc.h>
+
#include "drmtest.h"
#include "i915_drm.h"
#include "intel_chipset.h"
@@ -65,6 +67,10 @@
#include "igt_stats.h"
#include "igt_sysfs.h"
+#ifdef HAVE_LIBGEN_H
+#include <libgen.h> /* for dirname() */
+#endif
+
/**
* SECTION:igt_aux
* @short_description: Auxiliary libraries and support functions
@@ -1182,6 +1188,257 @@ void igt_set_module_param_int(const char *name, int val)
igt_set_module_param(name, str);
}
+/**
+ * igt_terminate_process:
+ * @sig: Signal to send
+ * @comm: 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 -errno otherwise.
+ *
+ * This function sends the signal @sig for a process found in process table
+ * with name @comm.
+ */
+int igt_terminate_process(int sig, const char *comm)
+{
+ PROCTAB *proc;
+ proc_t *proc_info;
+ int err = 0;
+
+ proc = openproc(PROC_FILLCOM | PROC_FILLSTAT | PROC_FILLARG);
+ igt_assert(proc != NULL);
+
+ while ((proc_info = readproc(proc, NULL))) {
+ if (!strncasecmp(proc_info->cmd, comm, sizeof(proc_info->cmd))) {
+
+ if (kill(proc_info->tid, sig) < 0)
+ err = -errno;
+
+ freeproc(proc_info);
+ break;
+ }
+ freeproc(proc_info);
+ }
+
+ closeproc(proc);
+ return err;
+}
+
+struct pinfo {
+ pid_t pid;
+ const char *comm;
+ const char *fn;
+};
+
+static void
+__igt_show_stat(struct pinfo *info)
+{
+ const char *comm, *fn;
+ const char *type = "";
+ struct stat st;
+
+ pid_t pid = info->pid;
+ igt_assert((comm = info->comm));
+ igt_assert((fn = info->fn));
+
+ if (lstat(fn, &st) == -1)
+ return;
+
+ igt_info("%20.20s ", comm);
+ igt_info("%10d ", pid);
+
+ switch (st.st_mode & S_IFMT) {
+ case S_IFBLK:
+ type = "block";
+ break;
+ case S_IFCHR:
+ type = "character";
+ break;
+ case S_IFDIR:
+ type = "directory";
+ break;
+ case S_IFIFO:
+ type = "FIFO/pipe";
+ break;
+ case S_IFLNK:
+ type = "symlink";
+ break;
+ case S_IFREG:
+ type = "file";
+ break;
+ case S_IFSOCK:
+ type = "socket";
+ break;
+ default:
+ type = "unknown?";
+ break;
+ }
+ igt_info("%20.20s ", type);
+
+ igt_info("%10ld%10ld ", (long) st.st_uid, (long) st.st_gid);
+
+ igt_info("%15lld bytes ", (long long) st.st_size);
+ igt_info("%30.30s", fn);
+ igt_info("\n");
+}
+
+
+static void
+igt_show_stat_header(void)
+{
+ igt_info("%20.20s%11.11s%21.21s%11.11s%10.10s%22.22s%31.31s\n",
+ "COMM", "PID", "Type", "UID", "GID", "Size", "Filename");
+}
+
+static void
+igt_show_stat(proc_t *info, int *state, const char *fn)
+{
+ struct pinfo p = { .pid = info->tid, .comm = info->cmd, .fn = fn };
+
+ if (!*state)
+ igt_show_stat_header();
+
+ __igt_show_stat(&p);
+ ++*state;
+}
+
+static void
+__igt_lsof_fds(proc_t *proc_info, int *state, char *proc_path, const char *dir)
+{
+ struct dirent *d;
+ struct stat st;
+ char path[PATH_MAX];
+ char *fd_lnk;
+
+ /* default fds or kernel threads */
+ const char *default_fds[] = { "/dev/pts", "/dev/null" };
+
+ DIR *dp = opendir(proc_path);
+ igt_assert(dp);
+again:
+ while ((d = readdir(dp))) {
+ char *copy_fd_lnk;
+ char *dirn;
+
+ unsigned int i;
+ ssize_t read;
+
+ if (*d->d_name == '.')
+ continue;
+
+ memset(path, 0, sizeof(path));
+ snprintf(path, sizeof(path), "%s/%s", proc_path, d->d_name);
+
+ if (lstat(path, &st) == -1)
+ continue;
+
+ fd_lnk = malloc(st.st_size + 1);
+
+ igt_assert((read = readlink(path, fd_lnk, st.st_size + 1)));
+ fd_lnk[read] = '\0';
+
+ for (i = 0; i < ARRAY_SIZE(default_fds); ++i) {
+ if (!strncmp(default_fds[i],
+ fd_lnk,
+ strlen(default_fds[i]))) {
+ free(fd_lnk);
+ goto again;
+ }
+ }
+
+ copy_fd_lnk = strdup(fd_lnk);
+ dirn = dirname(copy_fd_lnk);
+
+ if (!strncmp(dir, dirn, strlen(dir)))
+ igt_show_stat(proc_info, state, fd_lnk);
+
+ free(copy_fd_lnk);
+ free(fd_lnk);
+ }
+}
+
+/*
+ * This functions verifies, for each process running on the machine, if the
+ * current working directory or the fds matches the one supplied in dir.
+ */
+static void
+__igt_lsof(const char *dir)
+{
+ PROCTAB *proc;
+ proc_t *proc_info;
+
+ char path[PATH_MAX];
+ char *name_lnk;
+ struct stat st;
+ int state = 0;
+
+ proc = openproc(PROC_FILLCOM | PROC_FILLSTAT | PROC_FILLARG);
+ igt_assert(proc != NULL);
+
+ while ((proc_info = readproc(proc, NULL))) {
+ ssize_t read;
+
+ /* check current working directory */
+ memset(path, 0, sizeof(path));
+ snprintf(path, sizeof(path), "/proc/%d/cwd", proc_info->tid);
+
+ if (stat(path, &st) == -1)
+ continue;
+
+ name_lnk = malloc(st.st_size + 1);
+
+ igt_assert((read = readlink(path, name_lnk, st.st_size + 1)));
+ name_lnk[read] = '\0';
+
+ if (!strncmp(dir, name_lnk, strlen(dir)))
+ igt_show_stat(proc_info, &state, name_lnk);
+
+ /* check also fd, seems that lsof(8) doesn't look here */
+ memset(path, 0, sizeof(path));
+ snprintf(path, sizeof(path), "/proc/%d/fd", proc_info->tid);
+
+ __igt_lsof_fds(proc_info, &state, path, dir);
+
+ free(name_lnk);
+ freeproc(proc_info);
+ }
+
+ closeproc(proc);
+}
+
+/**
+ * igt_lsof: Lists information about files opened by processes.
+ * @dpath: Path to look under. A valid directory is required.
+ *
+ * This function mimics (a restrictive form of) lsof(8), but also shows
+ * information about opened fds.
+ */
+void
+igt_lsof(const char *dpath)
+{
+ struct stat st;
+ size_t len = strlen(dpath);
+ char *sanitized;
+
+ if (stat(dpath, &st) == -1)
+ return;
+
+ if (!S_ISDIR(st.st_mode)) {
+ igt_warn("%s not a directory!\n", dpath);
+ return;
+ }
+
+ sanitized = strdup(dpath);
+ /* remove last '/' so matching is easier */
+ if (len > 1 && dpath[len - 1] == '/')
+ sanitized[len - 1] = '\0';
+
+ __igt_lsof(sanitized);
+
+ free(sanitized);
+}
+
static struct igt_siglatency {
timer_t timer;
struct timespec target;