igt/gem_userptr_blits: Fix forked access test
[platform/upstream/intel-gpu-tools.git] / tests / gem_flink_race.c
1 /*
2  * Copyright (c) 2013 Intel Corporation
3  *
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:
10  *
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
13  * Software.
14  *
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
21  * IN THE SOFTWARE.
22  *
23  * Authors:
24  *    Daniel Vetter <daniel.vetter@ffwll.ch>
25  */
26
27 #define _GNU_SOURCE
28 #include <sys/ioctl.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <fcntl.h>
32 #include <unistd.h>
33 #include <pthread.h>
34 #include <errno.h>
35
36 #include "drmtest.h"
37 #include "ioctl_wrappers.h"
38 #include "intel_bufmgr.h"
39 #include "igt_debugfs.h"
40
41 /* Testcase: check for flink/open vs. gem close races
42  *
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.
45  */
46
47 /* We want lockless and I'm to lazy to dig out an atomic libarary. On x86 this
48  * works, too. */
49 volatile int pls_die = 0;
50 int fd;
51
52 static int get_object_count(void)
53 {
54         FILE *file;
55         int ret, scanned;
56         int device = drm_get_card();
57         char *path;
58
59         igt_drop_caches_set(DROP_RETIRE);
60
61         ret = asprintf(&path, "/sys/kernel/debug/dri/%d/i915_gem_objects", device);
62         igt_assert(ret != -1);
63
64         file = fopen(path, "r");
65
66         scanned = fscanf(file, "%i objects", &ret);
67         igt_assert(scanned == 1);
68
69         return ret;
70 }
71
72
73 static void *thread_fn_flink_name(void *p)
74 {
75         struct drm_gem_open open_struct;
76         int ret;
77
78         while (!pls_die) {
79                 memset(&open_struct, 0, sizeof(open_struct));
80
81                 open_struct.name = 1;
82                 ret = ioctl(fd, DRM_IOCTL_GEM_OPEN, &open_struct);
83                 if (ret == 0) {
84                         uint32_t name = gem_flink(fd, open_struct.handle);
85
86                         igt_assert(name == 1);
87
88                         gem_close(fd, open_struct.handle);
89                 } else
90                         igt_assert(errno == ENOENT);
91         }
92
93         return (void *)0;
94 }
95
96 static void test_flink_name(void)
97 {
98         pthread_t *threads;
99         int r, i, num_threads;
100         void *status;
101
102         num_threads = sysconf(_SC_NPROCESSORS_ONLN) - 1;
103         if (!num_threads)
104                 num_threads = 1;
105
106         threads = calloc(num_threads, sizeof(pthread_t));
107
108         fd = drm_open_any();
109         igt_assert(fd >= 0);
110
111         for (i = 0; i < num_threads; i++) {
112                 r = pthread_create(&threads[i], NULL,
113                                    thread_fn_flink_name, NULL);
114                 igt_assert(r == 0);
115         }
116
117         for (i = 0; i < 1000000; i++) {
118                 uint32_t handle;
119
120                 handle = gem_create(fd, 4096);
121
122                 gem_flink(fd, handle);
123
124                 gem_close(fd, handle);
125         }
126
127         pls_die = 1;
128
129         for (i = 0;  i < num_threads; i++) {
130                 pthread_join(threads[i], &status);
131                 igt_assert(status == 0);
132         }
133
134         close(fd);
135 }
136
137 static void *thread_fn_flink_close(void *p)
138 {
139         struct drm_gem_flink flink;
140         struct drm_gem_close close_bo;
141         uint32_t handle;
142
143         while (!pls_die) {
144                 /* We want to race gem close against flink on handle one.*/
145                 handle = gem_create(fd, 4096);
146                 if (handle != 1)
147                         gem_close(fd, handle);
148
149                 /* raw ioctl since we expect this to fail */
150                 flink.handle = 1;
151                 ioctl(fd, DRM_IOCTL_GEM_FLINK, &flink);
152
153                 close_bo.handle = 1;
154                 ioctl(fd, DRM_IOCTL_GEM_CLOSE, &close_bo);
155         }
156
157         return (void *)0;
158 }
159
160 static void test_flink_close(void)
161 {
162         pthread_t *threads;
163         int r, i, num_threads;
164         int obj_count;
165         void *status;
166         int fake;
167
168         /* Allocate exit handler fds in here so that we dont screw
169          * up the counts */
170         fake = drm_open_any();
171
172         obj_count = get_object_count();
173
174         num_threads = sysconf(_SC_NPROCESSORS_ONLN);
175
176         threads = calloc(num_threads, sizeof(pthread_t));
177
178         fd = drm_open_any();
179         igt_assert(fd >= 0);
180
181         for (i = 0; i < num_threads; i++) {
182                 r = pthread_create(&threads[i], NULL,
183                                    thread_fn_flink_close, NULL);
184                 igt_assert(r == 0);
185         }
186
187         sleep(5);
188
189         pls_die = 1;
190
191         for (i = 0;  i < num_threads; i++) {
192                 pthread_join(threads[i], &status);
193                 igt_assert(status == 0);
194         }
195
196         close(fd);
197
198         obj_count = get_object_count() - obj_count;
199
200         igt_info("leaked %i objects\n", obj_count);
201
202         close(fake);
203
204         igt_assert(obj_count == 0);
205 }
206
207 igt_main
208 {
209         igt_skip_on_simulation();
210
211         igt_subtest("flink_name")
212                 test_flink_name();
213
214         igt_subtest("flink_close")
215                 test_flink_close();
216 }