tests/gem_flink_race: actually make it somewhat useful
authorDaniel Vetter <daniel.vetter@ffwll.ch>
Wed, 24 Jul 2013 07:46:57 +0000 (09:46 +0200)
committerDaniel Vetter <daniel.vetter@ffwll.ch>
Wed, 24 Jul 2013 10:52:01 +0000 (12:52 +0200)
- Enable subtest support.

- Add a check for the same flink name in the racing threads, which is
  an issue one of my recent patches actually fixes.

- Add the test I've actually wanted to write which races an flink
  against gem close (with no open in between). That one does indeed
  leak.

- Readd the leak check, but note that this needs a fixed kernel.
  Otherwise the leak counter will be utter garbage.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
tests/Makefile.am
tests/gem_flink_race.c

index 5ad38fd..a59c25f 100644 (file)
@@ -25,6 +25,7 @@ TESTS_progs_M = \
        gem_exec_nop \
        gem_fence_thrash \
        gem_flink \
+       gem_flink_race \
        gem_gtt_concurrent_blit \
        gem_linear_blits \
        gem_mmap_gtt \
@@ -61,7 +62,6 @@ TESTS_progs = \
        gem_exec_faulting_reloc \
        gem_exec_lut_handle \
        gem_fenced_exec_thrash \
-       gem_flink_race \
        gem_gtt_cpu_tlb \
        gem_gtt_speed \
        gem_hangcheck_forcewake \
index a8bbfd3..522c92d 100644 (file)
@@ -24,6 +24,7 @@
  *    Daniel Vetter <daniel.vetter@ffwll.ch>
  */
 
+#define _GNU_SOURCE
 #include <sys/ioctl.h>
 #include <stdlib.h>
 #include <string.h>
 volatile int pls_die = 0;
 int fd;
 
-static void *thread_fn(void *p)
+static int get_object_count(void)
+{
+       FILE *file;
+       int ret, scanned;
+       int device = drm_get_card(0);
+       char *path;
+
+       ret = asprintf(&path, "/sys/kernel/debug/dri/%d/i915_gem_objects", device);
+       assert(ret != -1);
+
+       file = fopen(path, "r");
+
+       scanned = fscanf(file, "%i objects,", &ret);
+       assert(scanned == 1);
+
+       return ret;
+}
+
+
+static void *thread_fn_flink_name(void *p)
 {
        struct drm_gem_open open_struct;
        int ret;
@@ -57,24 +77,25 @@ static void *thread_fn(void *p)
 
                open_struct.name = 1;
                ret = ioctl(fd, DRM_IOCTL_GEM_OPEN, &open_struct);
-               if (ret == 0)
+               if (ret == 0) {
+                       uint32_t name = gem_flink(fd, open_struct.handle);
+
+                       assert(name == 1);
+
                        gem_close(fd, open_struct.handle);
-               else
+               else
                        assert(errno == ENOENT);
        }
 
        return (void *)0;
 }
 
-int main(int argc, char **argv)
+static void test_flink_name(void)
 {
-       int num_threads;
        pthread_t *threads;
-       int r, i;
+       int r, i, num_threads;
        void *status;
 
-       drmtest_skip_on_simulation();
-
        num_threads = sysconf(_SC_NPROCESSORS_ONLN) - 1;
        if (!num_threads)
                num_threads = 1;
@@ -85,7 +106,8 @@ int main(int argc, char **argv)
        assert(fd >= 0);
 
        for (i = 0; i < num_threads; i++) {
-               r = pthread_create(&threads[i], NULL, thread_fn, NULL);
+               r = pthread_create(&threads[i], NULL,
+                                  thread_fn_flink_name, NULL);
                assert(r == 0);
        }
 
@@ -110,6 +132,84 @@ int main(int argc, char **argv)
        assert(fd >= 0);
 
        close(fd);
+}
+
+static void *thread_fn_flink_close(void *p)
+{
+       struct drm_gem_flink flink;
+       struct drm_gem_close close_bo;
+       uint32_t handle;
+
+       while (!pls_die) {
+               /* We want to race gem close against flink on handle one.*/
+               handle = gem_create(fd, 4096);
+               if (handle != 1)
+                       gem_close(fd, handle);
+
+               /* raw ioctl since we expect this to fail */
+               flink.handle = 1;
+               ioctl(fd, DRM_IOCTL_GEM_FLINK, &flink);
+
+               close_bo.handle = 1;
+               ioctl(fd, DRM_IOCTL_GEM_CLOSE, &close_bo);
+       }
+
+       return (void *)0;
+}
+
+static void test_flink_close(void)
+{
+       pthread_t *threads;
+       int r, i, num_threads;
+       int obj_count = get_object_count();
+       void *status;
+
+       num_threads = sysconf(_SC_NPROCESSORS_ONLN) - 1;
+       if (!num_threads)
+               num_threads = 1;
+
+       threads = calloc(num_threads, sizeof(pthread_t));
+
+       fd = drm_open_any();
+       assert(fd >= 0);
+
+       for (i = 0; i < num_threads; i++) {
+               r = pthread_create(&threads[i], NULL,
+                                  thread_fn_flink_close, NULL);
+               assert(r == 0);
+       }
+
+       sleep(5);
+
+       pls_die = 1;
+
+       for (i = 0;  i < num_threads; i++) {
+               pthread_join(threads[i], &status);
+               assert(status == 0);
+       }
+
+       fd = drm_open_any();
+       assert(fd >= 0);
+
+       close(fd);
+
+       obj_count = get_object_count() - obj_count;
+
+       printf("leaked %i objects\n", obj_count);
+       assert(obj_count == 0);
+}
+
+int main(int argc, char **argv)
+{
+       drmtest_skip_on_simulation();
+
+       drmtest_subtest_init(argc, argv);
+
+       if (drmtest_run_subtest("flink_name"))
+               test_flink_name();
+
+       if (drmtest_run_subtest("flink_close"))
+               test_flink_close();
 
        return 0;
 }