summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--benchmarks/Makefile.am2
-rw-r--r--configure.ac14
-rw-r--r--debugger/Makefile.am2
-rw-r--r--demos/Makefile.am2
-rw-r--r--lib/Makefile.am2
-rw-r--r--lib/igt_aux.c188
-rw-r--r--lib/igt_aux.h8
-rw-r--r--lib/tests/Makefile.am2
-rw-r--r--tests/Makefile.am2
-rw-r--r--tools/Makefile.am2
10 files changed, 217 insertions, 7 deletions
diff --git a/benchmarks/Makefile.am b/benchmarks/Makefile.am
index a555ab6a..c67f4722 100644
--- a/benchmarks/Makefile.am
+++ b/benchmarks/Makefile.am
@@ -3,7 +3,7 @@ include Makefile.sources
AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/lib
AM_CFLAGS = $(DRM_CFLAGS) $(CWARNFLAGS) $(CAIRO_CFLAGS) $(LIBUNWIND_CFLAGS)
-LDADD = $(top_builddir)/lib/libintel_tools.la $(DRM_LIBS) $(PCIACCESS_LIBS) $(CAIRO_LIBS) $(LIBUNWIND_LIBS) -lm
+LDADD = $(top_builddir)/lib/libintel_tools.la $(DRM_LIBS) $(PCIACCESS_LIBS) $(CAIRO_LIBS) $(LIBUNWIND_LIBS) $(TIMER_LIBS) -lm
benchmarks_LTLIBRARIES = gem_exec_tracer.la
gem_exec_tracer_la_LDFLAGS = -module -avoid-version -no-undefined
diff --git a/configure.ac b/configure.ac
index e523b7a8..1024ad80 100644
--- a/configure.ac
+++ b/configure.ac
@@ -66,6 +66,20 @@ AC_CHECK_TYPES([sighandler_t],[],[],[AC_INCLUDES_DEFAULT
AC_CHECK_FUNCS([swapctl])
AC_CHECK_FUNCS([asprintf])
+dnl Check for POSIX timers
+AC_CHECK_FUNCS(timer_create, [], [
+ AC_CHECK_LIB(rt, timer_create, [
+ AC_DEFINE(HAVE_TIMER_CREATE, 1)
+ TIMER_LIBS="-lrt"
+ ], [
+ AC_CHECK_LIB(pthread, timer_create, [
+ AC_DEFINE(HAVE_TIMER_CREATE, 1)
+ TIMER_LIBS="-lpthread"
+ ])
+ ])
+])
+AC_SUBST(TIMER_LIBS)
+
# Initialize libtool
AC_DISABLE_STATIC
AC_PROG_LIBTOOL
diff --git a/debugger/Makefile.am b/debugger/Makefile.am
index 0b6028b4..5a523f5e 100644
--- a/debugger/Makefile.am
+++ b/debugger/Makefile.am
@@ -15,4 +15,4 @@ AM_CFLAGS = \
$(LIBUNWIND_CFLAGS) \
$(CWARNFLAGS)
-LDADD = $(top_builddir)/lib/libintel_tools.la $(DRM_LIBS) $(PCIACCESS_LIBS) $(CAIRO_LIBS) $(LIBUNWIND_LIBS)
+LDADD = $(top_builddir)/lib/libintel_tools.la $(DRM_LIBS) $(PCIACCESS_LIBS) $(CAIRO_LIBS) $(LIBUNWIND_LIBS) $(TIMER_LIBS)
diff --git a/demos/Makefile.am b/demos/Makefile.am
index 029581a6..d18a705f 100644
--- a/demos/Makefile.am
+++ b/demos/Makefile.am
@@ -4,4 +4,4 @@ bin_PROGRAMS = \
AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/lib
AM_CFLAGS = $(DRM_CFLAGS) $(PCIACCESS_CFLAGS) $(CWARNFLAGS) $(CAIRO_CFLAGS) $(LIBUNWIND_CFLAGS)
-LDADD = $(top_builddir)/lib/libintel_tools.la $(DRM_LIBS) $(PCIACCESS_LIBS) $(CAIRO_LIBS) $(LIBUNWIND_LIBS)
+LDADD = $(top_builddir)/lib/libintel_tools.la $(DRM_LIBS) $(PCIACCESS_LIBS) $(CAIRO_LIBS) $(LIBUNWIND_LIBS) $(TIMER_LIBS)
diff --git a/lib/Makefile.am b/lib/Makefile.am
index e3a456ba..a8a1eb6d 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -21,6 +21,6 @@ AM_CFLAGS = $(DRM_CFLAGS) $(CWARNFLAGS) $(LIBUNWIND_CFLAGS) $(DEBUG_CFLAGS) \
-DIGT_LOG_DOMAIN=\""$(subst _,-,$*)"\" \
-pthread
-LDADD = $(CAIRO_LIBS) $(LIBUNWIND_LIBS) -lm
+LDADD = $(CAIRO_LIBS) $(LIBUNWIND_LIBS) $(TIMER_LIBS) -lm
AM_CFLAGS += $(CAIRO_CFLAGS)
diff --git a/lib/igt_aux.c b/lib/igt_aux.c
index f38ecd84..336440c9 100644
--- a/lib/igt_aux.c
+++ b/lib/igt_aux.c
@@ -40,6 +40,7 @@
#include <signal.h>
#include <pciaccess.h>
#include <stdlib.h>
+#include <time.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/time.h>
@@ -73,6 +74,193 @@
/* signal interrupt helpers */
+
+#define MSEC_PER_SEC (1000)
+#define USEC_PER_SEC (1000*MSEC_PER_SEC)
+#define NSEC_PER_SEC (1000*USEC_PER_SEC)
+
+/* signal interrupt helpers */
+#define gettid() syscall(__NR_gettid)
+#define sigev_notify_thread_id _sigev_un._tid
+
+static struct __igt_sigiter {
+ pid_t tid;
+ timer_t timer;
+ struct timespec offset;
+ struct {
+ long hit, miss;
+ long ioctls, signals;
+ } stat;
+} __igt_sigiter;
+
+static void sigiter(int sig, siginfo_t *info, void *arg)
+{
+ __igt_sigiter.stat.signals++;
+}
+
+#if 0
+#define SIG_ASSERT(expr) igt_assert(expr)
+#else
+#define SIG_ASSERT(expr)
+#endif
+
+static int
+sig_ioctl(int fd, unsigned long request, void *arg)
+{
+ struct itimerspec its;
+ int ret;
+
+ SIG_ASSERT(__igt_sigiter.timer);
+ SIG_ASSERT(__igt_sigiter.tid == gettid());
+
+ memset(&its, 0, sizeof(its));
+ its.it_value = __igt_sigiter.offset;
+ do {
+ long serial;
+
+ __igt_sigiter.stat.ioctls++;
+
+ ret = 0;
+ serial = __igt_sigiter.stat.signals;
+ igt_assert(timer_settime(__igt_sigiter.timer, 0, &its, NULL) == 0);
+ if (ioctl(fd, request, arg))
+ ret = errno;
+ if (__igt_sigiter.stat.signals == serial)
+ __igt_sigiter.stat.miss++;
+ if (ret == 0)
+ break;
+
+ if (ret == EINTR) {
+ __igt_sigiter.stat.hit++;
+
+ its.it_value.tv_sec *= 2;
+ its.it_value.tv_nsec *= 2;
+ while (its.it_value.tv_nsec >= NSEC_PER_SEC) {
+ its.it_value.tv_nsec -= NSEC_PER_SEC;
+ its.it_value.tv_sec += 1;
+ }
+
+ SIG_ASSERT(its.it_value.tv_nsec >= 0);
+ SIG_ASSERT(its.it_value.tv_sec >= 0);
+ }
+ } while (ret == EAGAIN || ret == EINTR);
+
+ memset(&its, 0, sizeof(its));
+ timer_settime(__igt_sigiter.timer, 0, &its, NULL);
+
+ errno = ret;
+ return ret ? -1 : 0;
+}
+
+static bool igt_sigiter_start(struct igt_sigiter *iter, bool enable)
+{
+ /* Note that until we can automatically clean up on failed/skipped
+ * tests, we cannot assume the state of the igt_ioctl indirection.
+ */
+ SIG_ASSERT(igt_ioctl == drmIoctl);
+ igt_ioctl = drmIoctl;
+
+ if (enable) {
+ struct sigevent sev;
+ struct sigaction act;
+
+ igt_ioctl = sig_ioctl;
+ __igt_sigiter.tid = gettid();
+
+ memset(&sev, 0, sizeof(sev));
+ sev.sigev_notify = SIGEV_SIGNAL | SIGEV_THREAD_ID;
+ sev.sigev_notify_thread_id = __igt_sigiter.tid;
+ sev.sigev_signo = SIGRTMIN;
+ igt_assert(timer_create(CLOCK_MONOTONIC, &sev, &__igt_sigiter.timer) == 0);
+
+ memset(&act, 0, sizeof(act));
+ act.sa_sigaction = sigiter;
+ act.sa_flags = SA_SIGINFO;
+ igt_assert(sigaction(SIGRTMIN, &act, NULL) == 0);
+
+ __igt_sigiter.offset.tv_sec = 0;
+ __igt_sigiter.offset.tv_nsec = 50;
+ }
+
+ return true;
+}
+
+static bool igt_sigiter_stop(struct igt_sigiter *iter, bool enable)
+{
+ if (enable) {
+ struct sigaction act;
+
+ SIG_ASSERT(igt_ioctl == sig_ioctl);
+ SIG_ASSERT(__igt_sigiter.tid == gettid());
+ igt_ioctl = drmIoctl;
+
+ timer_delete(__igt_sigiter.timer);
+
+ memset(&act, 0, sizeof(act));
+ act.sa_handler = SIG_IGN;
+ sigaction(SIGRTMIN, &act, NULL);
+
+ memset(&__igt_sigiter, 0, sizeof(__igt_sigiter));
+ }
+
+ memset(iter, 0, sizeof(*iter));
+ return false;
+}
+
+/**
+ * igt_sigiter_continue:
+ * @iter: the control struct
+ * @enable: a boolean as to whether or not we want to enable interruptions
+ *
+ * Provides control flow such that all drmIoctl() (strictly igt_ioctl())
+ * within the loop are forcibly injected with signals (SIGRTMIN).
+ *
+ * This is useful to exercise ioctl error paths, at least where those can be
+ * exercises by interrupting blocking waits, like stalling for the gpu.
+ *
+ * igt_sigiter_continue() returns false when it has detected that it
+ * cannot inject any more signals in the ioctls from previous runs.
+ *
+ * Typical usage is
+ * struct igt_sigiter iter = {};
+ * while (igt_sigiter_continue(&iter, test_flags & TEST_INTERRUPTIBLE))
+ * do_test();
+ *
+ * This is condensed into the igt_interruptible() macro.
+ *
+ * Note that since this overloads the igt_ioctl(), this method is not useful
+ * for widespread signal injection, for example providing coverage of
+ * pagefaults. To interrupt everything, see igt_fork_signal_helper().
+ */
+bool igt_sigiter_continue(struct igt_sigiter *iter, bool enable)
+{
+ if (iter->pass++ == 0)
+ return igt_sigiter_start(iter, enable);
+
+ if (__igt_sigiter.stat.miss == __igt_sigiter.stat.ioctls)
+ return igt_sigiter_stop(iter, enable);
+
+ igt_debug("%s: pass %d, missed %ld/%ld\n",
+ __func__, iter->pass - 1,
+ __igt_sigiter.stat.miss,
+ __igt_sigiter.stat.ioctls);
+
+ SIG_ASSERT(igt_ioctl == sig_ioctl);
+ SIG_ASSERT(__igt_sigiter.timer);
+
+ __igt_sigiter.offset.tv_sec *= 2;
+ __igt_sigiter.offset.tv_nsec *= 2;
+ while (__igt_sigiter.offset.tv_nsec >= NSEC_PER_SEC) {
+ __igt_sigiter.offset.tv_nsec -= NSEC_PER_SEC;
+ __igt_sigiter.offset.tv_sec += 1;
+ }
+ SIG_ASSERT(__igt_sigiter.offset.tv_nsec >= 0);
+ SIG_ASSERT(__igt_sigiter.offset.tv_sec >= 0);
+
+ memset(&__igt_sigiter.stat, 0, sizeof(__igt_sigiter.stat));
+ return true;
+}
+
static struct igt_helper_process signal_helper;
long long int sig_stat;
static void __attribute__((noreturn)) signal_helper_process(pid_t pid)
diff --git a/lib/igt_aux.h b/lib/igt_aux.h
index 427719ef..eabeefd2 100644
--- a/lib/igt_aux.h
+++ b/lib/igt_aux.h
@@ -40,6 +40,14 @@ extern int num_trash_bos;
void igt_fork_signal_helper(void);
void igt_stop_signal_helper(void);
+struct igt_sigiter {
+ unsigned pass;
+};
+
+bool igt_sigiter_continue(struct igt_sigiter *iter, bool interrupt);
+#define igt_interruptible(E) \
+ for (struct igt_sigiter iter__={}; igt_sigiter_continue(&iter__, (E)); )
+
void igt_exchange_int(void *array, unsigned i, unsigned j);
void igt_permute_array(void *array, unsigned size,
void (*exchange_func)(void *array,
diff --git a/lib/tests/Makefile.am b/lib/tests/Makefile.am
index f09d2fe7..582cc3e9 100644
--- a/lib/tests/Makefile.am
+++ b/lib/tests/Makefile.am
@@ -13,7 +13,7 @@ AM_CFLAGS = $(DRM_CFLAGS) $(CWARNFLAGS) $(DEBUG_CFLAGS) \
-DIGT_DATADIR=\""$(abs_srcdir)"\" \
$(NULL)
-LDADD = ../libintel_tools.la $(PCIACCESS_LIBS) $(DRM_LIBS) $(LIBUNWIND_LIBS)
+LDADD = ../libintel_tools.la $(PCIACCESS_LIBS) $(DRM_LIBS) $(LIBUNWIND_LIBS) $(TIMER_LIBS)
LDADD += $(CAIRO_LIBS) $(LIBUDEV_LIBS) $(GLIB_LIBS) -lm
AM_CFLAGS += $(CAIRO_CFLAGS) $(LIBUDEV_CFLAGS) $(GLIB_CFLAGS)
diff --git a/tests/Makefile.am b/tests/Makefile.am
index f72f7c0f..0ed40f7d 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -56,7 +56,7 @@ AM_CFLAGS = $(DRM_CFLAGS) $(CWARNFLAGS) $(DEBUG_CFLAGS)\
$(LIBUNWIND_CFLAGS) \
$(NULL)
-LDADD = ../lib/libintel_tools.la $(PCIACCESS_LIBS) $(DRM_LIBS) $(LIBUNWIND_LIBS)
+LDADD = ../lib/libintel_tools.la $(PCIACCESS_LIBS) $(DRM_LIBS) $(LIBUNWIND_LIBS) $(TIMER_LIBS)
LDADD += $(CAIRO_LIBS) $(LIBUDEV_LIBS) $(GLIB_LIBS) -lm
AM_CFLAGS += $(CAIRO_CFLAGS) $(LIBUDEV_CFLAGS) $(GLIB_CFLAGS)
diff --git a/tools/Makefile.am b/tools/Makefile.am
index 90a8ec1b..74c55218 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -4,7 +4,7 @@ SUBDIRS = null_state_gen registers
AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/lib
AM_CFLAGS = $(DEBUG_CFLAGS) $(DRM_CFLAGS) $(PCIACCESS_CFLAGS) $(CWARNFLAGS) $(CAIRO_CFLAGS) $(LIBUNWIND_CFLAGS) -DPKGDATADIR=\"$(pkgdatadir)\"
-LDADD = $(top_builddir)/lib/libintel_tools.la $(DRM_LIBS) $(PCIACCESS_LIBS) $(CAIRO_LIBS) $(LIBUDEV_LIBS) $(LIBUNWIND_LIBS) -lm
+LDADD = $(top_builddir)/lib/libintel_tools.la $(DRM_LIBS) $(PCIACCESS_LIBS) $(CAIRO_LIBS) $(LIBUDEV_LIBS) $(LIBUNWIND_LIBS) $(TIMER_LIBS) -lm
AM_LDFLAGS = -Wl,--as-needed