From 4901b5ff0e882b0b4e80d0adcbbf0c0f2a524560 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 25 Jul 2013 21:09:43 +0200 Subject: [PATCH] tests/prime_self_import: Add racing handle2fd testcase Similar to how we test flink races. Note that on unfixed kernels this oopses, and with my current set of patches it still leaks like mad. v2: Only close the prime fd if we've successfully created it. v3: Add a reimport test to check whether we don't race when reaping the obj->dma_buf link. Signed-off-by: Daniel Vetter --- tests/Makefile.am | 1 + tests/prime_self_import.c | 161 +++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 161 insertions(+), 1 deletion(-) diff --git a/tests/Makefile.am b/tests/Makefile.am index cc9f780..a22bf6c 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -195,6 +195,7 @@ gem_fence_thrash_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS) gem_fence_thrash_LDADD = $(LDADD) -lpthread gem_flink_race_LDADD = $(LDADD) -lpthread gem_threaded_access_tiled_LDADD = $(LDADD) -lpthread +prime_self_import_LDADD = $(LDADD) -lpthread gem_wait_render_timeout_LDADD = $(LDADD) -lrt kms_flip_LDADD = $(LDADD) -lrt diff --git a/tests/prime_self_import.c b/tests/prime_self_import.c index abdc220..b8b91e7 100644 --- a/tests/prime_self_import.c +++ b/tests/prime_self_import.c @@ -1,5 +1,5 @@ /* - * Copyright © 2012 Intel Corporation + * Copyright © 2012-2013 Intel Corporation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -31,6 +31,7 @@ * ... but with different fds, i.e. the wayland usecase. */ +#define _GNU_SOURCE #include #include #include @@ -42,6 +43,8 @@ #include #include #include +#include + #include "drm.h" #include "i915_drm.h" #include "drmtest.h" @@ -51,6 +54,7 @@ #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) static char counter; +volatile int pls_die = 0; static void check_bo(int fd1, uint32_t handle1, int fd2, uint32_t handle2) @@ -184,6 +188,159 @@ static void test_with_one_bo(void) check_bo(fd2, handle_import1, fd2, handle_import1); } +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_reimport_vs_close(void *p) +{ + struct drm_gem_close close_bo; + int *fds = p; + int fd = fds[0]; + int dma_buf_fd = fds[1]; + uint32_t handle; + + while (!pls_die) { + handle = prime_fd_to_handle(fd, dma_buf_fd); + + close_bo.handle = handle; + ioctl(fd, DRM_IOCTL_GEM_CLOSE, &close_bo); + } + + return (void *)0; +} + +static void test_reimport_close_race(void) +{ + pthread_t *threads; + int r, i, num_threads; + int fds[2]; + int obj_count = get_object_count(); + void *status; + uint32_t handle; + + num_threads = sysconf(_SC_NPROCESSORS_ONLN); + + threads = calloc(num_threads, sizeof(pthread_t)); + + fds[0] = drm_open_any(); + assert(fds[0] >= 0); + + handle = gem_create(fds[0], BO_SIZE); + + fds[1] = prime_handle_to_fd(fds[0], handle); + + for (i = 0; i < num_threads; i++) { + r = pthread_create(&threads[i], NULL, + thread_fn_reimport_vs_close, + (void *)(uintptr_t)fds); + assert(r == 0); + } + + sleep(5); + + pls_die = 1; + + for (i = 0; i < num_threads; i++) { + pthread_join(threads[i], &status); + assert(status == 0); + } + + close(fds[0]); + close(fds[1]); + + obj_count = get_object_count() - obj_count; + + printf("leaked %i objects\n", obj_count); + assert(obj_count == 0); +} + +static void *thread_fn_export_vs_close(void *p) +{ + struct drm_prime_handle prime_h2f; + struct drm_gem_close close_bo; + int fd = (uintptr_t)p; + 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 */ + + /* WTF: for gem_flink_race I've unconditionally used handle == 1 + * here, but with prime it seems to help a _lot_ to use + * something more random. */ + prime_h2f.handle = 1; + prime_h2f.flags = DRM_CLOEXEC; + prime_h2f.fd = -1; + + ioctl(fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &prime_h2f); + + close_bo.handle = 1; + ioctl(fd, DRM_IOCTL_GEM_CLOSE, &close_bo); + + close(prime_h2f.fd); + } + + return (void *)0; +} + +static void test_export_close_race(void) +{ + pthread_t *threads; + int r, i, num_threads; + int fd; + int obj_count = get_object_count(); + void *status; + + num_threads = sysconf(_SC_NPROCESSORS_ONLN); + + 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_export_vs_close, + (void *)(uintptr_t)fd); + assert(r == 0); + } + + sleep(5); + + pls_die = 1; + + for (i = 0; i < num_threads; i++) { + pthread_join(threads[i], &status); + assert(status == 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) { struct { @@ -193,6 +350,8 @@ int main(int argc, char **argv) { "with_one_bo", test_with_one_bo }, { "with_two_bos", test_with_two_bos }, { "with_fd_dup", test_with_fd_dup }, + { "export-vs-gem_close-race", test_export_close_race }, + { "reimport-vs-gem_close-race", test_reimport_close_race }, }; int i; -- 2.7.4