diff options
author | Peter Hutterer <peter.hutterer@who-t.net> | 2016-07-05 09:41:51 +1000 |
---|---|---|
committer | Peter Hutterer <peter.hutterer@who-t.net> | 2016-07-05 11:28:43 +1000 |
commit | 030ec053fbbc17f9bd0a3a8c6003318864986de7 (patch) | |
tree | a9760920923f02dcf585e93007ba36657ca0b2ea | |
parent | b5ea4137244ec8f8e1cbd0f61e655dd114a45110 (diff) |
test: create a lock file to avoid parallel udev reloads during device add
litest_add_device and litest_delete_device trigger a udev rule reload. This
messes with some test devices and when we run multiple tests in parallel we
get weird errors like "keyboard $BLAH failed the touchpad sanity test".
Still not 100% reliable to run tests in parallel, but it's vastly improved
now.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Jonas Ã…dahl <jadahl@gmail.com>
-rw-r--r-- | configure.ac | 3 | ||||
-rw-r--r-- | test/litest.c | 63 |
2 files changed, 66 insertions, 0 deletions
diff --git a/configure.ac b/configure.ac index 8c14efe6..3e973d42 100644 --- a/configure.ac +++ b/configure.ac @@ -194,6 +194,9 @@ if test "x$build_tests" = "xyes"; then AC_DEFINE_UNQUOTED(HAVE_ADDR2LINE, 1, [addr2line found]) AC_DEFINE_UNQUOTED(ADDR2LINE, ["$ADDR2LINE"], [Path to addr2line]) fi + + AC_DEFINE(LITEST_UDEV_LOCKFILE, ["/tmp/litest-udev.lock"], + [Lock file used to restrict udev reloads during tests]) fi AM_CONDITIONAL(HAVE_LIBUNWIND, [test "x$HAVE_LIBUNWIND" = xyes]) diff --git a/test/litest.c b/test/litest.c index 9b4feed6..1250b3f3 100644 --- a/test/litest.c +++ b/test/litest.c @@ -1164,6 +1164,58 @@ litest_restore_log_handler(struct libinput *libinput) libinput_log_set_handler(libinput, litest_log_handler); } +static inline int +create_udev_lock_file(void) +{ + int lfd; + + /* Running the multiple tests in parallel usually trips over udev + * not being up-to-date. We change the udev rules for every device + * created, sometimes this means we end up getting the wrong udev + * device, or having wrong properties applied. + * + * litests use the path interface and there is a window between + * creating the device (which triggers udev reloads) and adding the + * device to the libinput context where another udev reload may + * upset things. + * + * To avoid this, create a lockfile on device add and device delete + * to make sure that we have exclusive access to udev while + * the udev rules are reloaded. + */ + do { + lfd = open(LITEST_UDEV_LOCKFILE, O_CREAT|O_EXCL, O_RDWR); + + if (lfd == -1) { + struct stat st; + time_t now = time(NULL); + + litest_assert_int_eq(errno, EEXIST); + msleep(10); + + /* If the lock file is older than 10s, it's a + leftover from some aborted test */ + if (stat(LITEST_UDEV_LOCKFILE, &st) != -1) { + if (st.st_mtime < now - 10) { + fprintf(stderr, + "Removing stale lock file %s.\n", + LITEST_UDEV_LOCKFILE); + unlink(LITEST_UDEV_LOCKFILE); + } + } + } + } while (lfd < 0); + + return lfd; +} + +static inline void +delete_udev_lock_file(int lfd) +{ + close(lfd); + unlink(LITEST_UDEV_LOCKFILE); +} + struct litest_device * litest_add_device_with_overrides(struct libinput *libinput, enum litest_device_type which, @@ -1177,6 +1229,8 @@ litest_add_device_with_overrides(struct libinput *libinput, int rc; const char *path; + int lfd = create_udev_lock_file(); + d = litest_create(which, name_override, id_override, @@ -1202,6 +1256,9 @@ litest_add_device_with_overrides(struct libinput *libinput, d->interface->min[ABS_Y] = libevdev_get_abs_minimum(d->evdev, ABS_Y); d->interface->max[ABS_Y] = libevdev_get_abs_maximum(d->evdev, ABS_Y); } + + delete_udev_lock_file(lfd); + return d; } @@ -1258,9 +1315,13 @@ litest_handle_events(struct litest_device *d) void litest_delete_device(struct litest_device *d) { + int lfd; + if (!d) return; + lfd = create_udev_lock_file(); + if (d->udev_rule_file) { unlink(d->udev_rule_file); free(d->udev_rule_file); @@ -1278,6 +1339,8 @@ litest_delete_device(struct litest_device *d) free(d->private); memset(d,0, sizeof(*d)); free(d); + + delete_udev_lock_file(lfd); } void |