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>
38 #include "intel_bufmgr.h"
40 /* Testcase: check for flink/open vs. gem close races
42 * The gem flink open ioctl had a little race with gem close which could result
43 * in the flink name and corresponding reference getting leaked.
46 /* We want lockless and I'm to lazy to dig out an atomic libarary. On x86 this
48 volatile int pls_die = 0;
51 static int get_object_count(void)
55 int device = drm_get_card(0);
58 ret = asprintf(&path, "/sys/kernel/debug/dri/%d/i915_gem_objects", device);
61 file = fopen(path, "r");
63 scanned = fscanf(file, "%i objects", &ret);
70 static void *thread_fn_flink_name(void *p)
72 struct drm_gem_open open_struct;
76 memset(&open_struct, 0, sizeof(open_struct));
79 ret = ioctl(fd, DRM_IOCTL_GEM_OPEN, &open_struct);
81 uint32_t name = gem_flink(fd, open_struct.handle);
85 gem_close(fd, open_struct.handle);
87 assert(errno == ENOENT);
93 static void test_flink_name(void)
96 int r, i, num_threads;
99 num_threads = sysconf(_SC_NPROCESSORS_ONLN) - 1;
103 threads = calloc(num_threads, sizeof(pthread_t));
108 for (i = 0; i < num_threads; i++) {
109 r = pthread_create(&threads[i], NULL,
110 thread_fn_flink_name, NULL);
114 for (i = 0; i < 1000000; i++) {
117 handle = gem_create(fd, 4096);
119 gem_flink(fd, handle);
121 gem_close(fd, handle);
126 for (i = 0; i < num_threads; i++) {
127 pthread_join(threads[i], &status);
134 static void *thread_fn_flink_close(void *p)
136 struct drm_gem_flink flink;
137 struct drm_gem_close close_bo;
141 /* We want to race gem close against flink on handle one.*/
142 handle = gem_create(fd, 4096);
144 gem_close(fd, handle);
146 /* raw ioctl since we expect this to fail */
148 ioctl(fd, DRM_IOCTL_GEM_FLINK, &flink);
151 ioctl(fd, DRM_IOCTL_GEM_CLOSE, &close_bo);
157 static void test_flink_close(void)
160 int r, i, num_threads;
161 int obj_count = get_object_count();
164 num_threads = sysconf(_SC_NPROCESSORS_ONLN);
166 threads = calloc(num_threads, sizeof(pthread_t));
171 for (i = 0; i < num_threads; i++) {
172 r = pthread_create(&threads[i], NULL,
173 thread_fn_flink_close, NULL);
181 for (i = 0; i < num_threads; i++) {
182 pthread_join(threads[i], &status);
188 obj_count = get_object_count() - obj_count;
190 printf("leaked %i objects\n", obj_count);
191 assert(obj_count == 0);
194 int main(int argc, char **argv)
196 drmtest_skip_on_simulation();
198 drmtest_subtest_init(argc, argv);
200 drmtest_subtest("flink_name")
203 drmtest_subtest("flink_close")