summaryrefslogtreecommitdiff
path: root/tests/prime_self_import.c
diff options
context:
space:
mode:
authorDaniel Vetter <daniel.vetter@ffwll.ch>2013-07-25 21:09:43 +0200
committerDaniel Vetter <daniel.vetter@ffwll.ch>2013-08-06 21:59:55 +0200
commit4901b5ff0e882b0b4e80d0adcbbf0c0f2a524560 (patch)
tree39e5ce564ae8a42eb4c2ec9e702334ad82857415 /tests/prime_self_import.c
parent9ff5161354f2f8023e08eb87ebc173c01c2f607a (diff)
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 <daniel.vetter@ffwll.ch>
Diffstat (limited to 'tests/prime_self_import.c')
-rw-r--r--tests/prime_self_import.c161
1 files changed, 160 insertions, 1 deletions
diff --git a/tests/prime_self_import.c b/tests/prime_self_import.c
index abdc2201..b8b91e72 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 <unistd.h>
#include <stdlib.h>
#include <stdio.h>
@@ -42,6 +43,8 @@
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
+#include <pthread.h>
+
#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;