diff options
-rw-r--r-- | benchmarks/Makefile.am | 2 | ||||
-rw-r--r-- | configure.ac | 14 | ||||
-rw-r--r-- | debugger/Makefile.am | 2 | ||||
-rw-r--r-- | demos/Makefile.am | 2 | ||||
-rw-r--r-- | lib/Makefile.am | 2 | ||||
-rw-r--r-- | lib/igt_aux.c | 188 | ||||
-rw-r--r-- | lib/igt_aux.h | 8 | ||||
-rw-r--r-- | lib/tests/Makefile.am | 2 | ||||
-rw-r--r-- | tests/Makefile.am | 2 | ||||
-rw-r--r-- | tools/Makefile.am | 2 |
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 |