2 * Copyright (c) 2013 Intel Corporation
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24 * Daniel Vetter <daniel.vetter@ffwll.ch>
28 #include <sys/ioctl.h>
37 #include "ioctl_wrappers.h"
38 #include "intel_bufmgr.h"
39 #include "igt_debugfs.h"
41 /* Testcase: check for flink/open vs. gem close races
43 * The gem flink open ioctl had a little race with gem close which could result
44 * in the flink name and corresponding reference getting leaked.
47 /* We want lockless and I'm to lazy to dig out an atomic libarary. On x86 this
49 volatile int pls_die = 0;
52 static int get_object_count(void)
56 int device = drm_get_card();
59 igt_drop_caches_set(DROP_RETIRE);
61 ret = asprintf(&path, "/sys/kernel/debug/dri/%d/i915_gem_objects", device);
62 igt_assert(ret != -1);
64 file = fopen(path, "r");
66 scanned = fscanf(file, "%i objects", &ret);
67 igt_assert(scanned == 1);
73 static void *thread_fn_flink_name(void *p)
75 struct drm_gem_open open_struct;
79 memset(&open_struct, 0, sizeof(open_struct));
82 ret = ioctl(fd, DRM_IOCTL_GEM_OPEN, &open_struct);
84 uint32_t name = gem_flink(fd, open_struct.handle);
86 igt_assert(name == 1);
88 gem_close(fd, open_struct.handle);
90 igt_assert(errno == ENOENT);
96 static void test_flink_name(void)
99 int r, i, num_threads;
102 num_threads = sysconf(_SC_NPROCESSORS_ONLN) - 1;
106 threads = calloc(num_threads, sizeof(pthread_t));
111 for (i = 0; i < num_threads; i++) {
112 r = pthread_create(&threads[i], NULL,
113 thread_fn_flink_name, NULL);
117 for (i = 0; i < 1000000; i++) {
120 handle = gem_create(fd, 4096);
122 gem_flink(fd, handle);
124 gem_close(fd, handle);
129 for (i = 0; i < num_threads; i++) {
130 pthread_join(threads[i], &status);
131 igt_assert(status == 0);
137 static void *thread_fn_flink_close(void *p)
139 struct drm_gem_flink flink;
140 struct drm_gem_close close_bo;
144 /* We want to race gem close against flink on handle one.*/
145 handle = gem_create(fd, 4096);
147 gem_close(fd, handle);
149 /* raw ioctl since we expect this to fail */
151 ioctl(fd, DRM_IOCTL_GEM_FLINK, &flink);
154 ioctl(fd, DRM_IOCTL_GEM_CLOSE, &close_bo);
160 static void test_flink_close(void)
163 int r, i, num_threads;
168 /* Allocate exit handler fds in here so that we dont screw
170 fake = drm_open_any();
172 obj_count = get_object_count();
174 num_threads = sysconf(_SC_NPROCESSORS_ONLN);
176 threads = calloc(num_threads, sizeof(pthread_t));
181 for (i = 0; i < num_threads; i++) {
182 r = pthread_create(&threads[i], NULL,
183 thread_fn_flink_close, NULL);
191 for (i = 0; i < num_threads; i++) {
192 pthread_join(threads[i], &status);
193 igt_assert(status == 0);
198 obj_count = get_object_count() - obj_count;
200 igt_info("leaked %i objects\n", obj_count);
204 igt_assert(obj_count == 0);
209 igt_skip_on_simulation();
211 igt_subtest("flink_name")
214 igt_subtest("flink_close")