xref: /aosp_15_r20/external/igt-gpu-tools/tests/drm_import_export.c (revision d83cc019efdc2edc6c4b16e9034a3ceb8d35d77c)
1 /*
2  * Copyright © 2014 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 <[email protected]>
25  */
26 
27 #include "igt.h"
28 #include <stdio.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <fcntl.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <drm.h>
35 #include <i915_drm.h>
36 #include <xf86drm.h>
37 #include <intel_bufmgr.h>
38 #include <errno.h>
39 #include <pthread.h>
40 #include <unistd.h>
41 #include <sys/syscall.h>
42 
43 
44 int fd;
45 drm_intel_bufmgr *bufmgr;
46 int fd1;
47 drm_intel_bufmgr *bufmgr1;
48 
49 bool use_flink;
50 
new_buffers(void)51 static void new_buffers(void)
52 {
53 	unsigned int *buf1;
54 	drm_intel_bo *bo1, *bo2;
55 
56 
57 	bo1 = drm_intel_bo_alloc(bufmgr, "buf1",16384, 4096);
58 	igt_assert(bo1);
59 	drm_intel_bo_map(bo1, 1);
60 	bo2 = drm_intel_bo_alloc(bufmgr, "buf2", 16384, 4096);
61 	igt_assert(bo2);
62 	drm_intel_bo_map(bo2, 1);
63 
64 	buf1 = (unsigned int *)bo1->virtual;
65 	igt_assert(buf1);
66 	memset(buf1, 0, 16384);
67 	buf1[4000]=0x05000000;
68 
69 	drm_intel_bo_exec(bo1, 16384, NULL, 0,0);
70 	drm_intel_bo_wait_rendering(bo1);
71 
72 	drm_intel_bo_unmap( bo1 );
73 	drm_intel_bo_unreference(bo1);
74 
75 	drm_intel_bo_unmap( bo2 );
76 	drm_intel_bo_unreference(bo2);
77 }
78 
test_surfaces(drm_intel_bo * bo_shared)79 static void test_surfaces(drm_intel_bo *bo_shared)
80 {
81 	drm_intel_bo * bo;
82 	int loop=2;
83 
84 	while(loop--) {
85 		if (use_flink) {
86 			uint32_t name;
87 			drm_intel_bo_flink(bo_shared, &name);
88 			bo = drm_intel_bo_gem_create_from_name(bufmgr,
89 							       "shared resource",
90 							       name);
91 		} else {
92 			int prime_fd;
93 
94 			drm_intel_bo_gem_export_to_prime(bo_shared, &prime_fd);
95 			bo = drm_intel_bo_gem_create_from_prime(bufmgr,
96 								prime_fd, 4096);
97 			close(prime_fd);
98 		}
99 
100 		igt_assert(bo);
101 		new_buffers();
102 		drm_intel_bo_unreference(bo);
103 	}
104 }
105 
start_test(void)106 static void start_test(void)
107 {
108 	int i;
109 
110 	for (i=0; i < 16384; i++)
111 	{
112 		drm_intel_bo * bo_shared;
113 
114 		bo_shared = drm_intel_bo_alloc(bufmgr1, "buf-shared",16384, 4096);
115 		test_surfaces(bo_shared);
116 		drm_intel_bo_unreference(bo_shared);
117 	}
118 }
119 
test_thread(void * par)120 static void * test_thread(void * par)
121 {
122 #ifdef __linux__
123 	igt_debug("start %ld\n", (long) gettid());
124 #else
125 	igt_debug("start %ld\n", (long) pthread_self());
126 #endif
127 	start_test();
128 
129 	return NULL;
130 }
131 
132 struct import_race_thread_data {
133 	int prime_fd;
134 	uint32_t flink_name;
135 	unsigned int stop;
136 	pthread_mutex_t mutex;
137 };
138 
139 /*
140  * Attempt to import the bo. It is possible that GEM_CLOSE was already called
141  * in different thread and from i915 point of view the handle is no longer
142  * valid (thus create_from_prime/name should fail).
143  */
import_close_thread(void * data)144 static void *import_close_thread(void *data)
145 {
146 	struct import_race_thread_data *t = (struct import_race_thread_data *)data;
147 	drm_intel_bo *bo;
148 	pthread_mutex_lock(&t->mutex);
149 	while (!t->stop) {
150 		pthread_mutex_unlock(&t->mutex);
151 		bo = NULL;
152 		if (use_flink)
153 			bo = drm_intel_bo_gem_create_from_name(bufmgr, "buf-shared", t->flink_name);
154 		else {
155 			pthread_mutex_lock(&t->mutex);
156 			if (t->prime_fd != -1) {
157 				bo = drm_intel_bo_gem_create_from_prime(bufmgr, t->prime_fd, 4096);
158 				pthread_mutex_unlock(&t->mutex);
159 			}
160 			else
161 				/* Lock should be held on entering the loop */
162 				continue;
163 		}
164 
165 		if (bo == NULL) {
166 			/*
167 			 * If the bo is NULL it means that we've unreferenced in other
168 			 * thread - therefore we should expect ENOENT
169 			 */
170 			igt_assert_eq(errno, ENOENT);
171 		} else {
172 			drm_intel_bo_unreference(bo);
173 		}
174 
175 		pthread_mutex_lock(&t->mutex);
176 	}
177 	pthread_mutex_unlock(&t->mutex);
178 
179 	return NULL;
180 }
181 
182 /*
183  * It is possible to race between unreference of the underlying BO and importing
184  * it from prime_fd/name. Verify that the behaviour of libdrm is consistent for
185  * prime/flink.
186  */
test_import_close_race(void)187 static void test_import_close_race(void)
188 {
189 	pthread_t t;
190 	drm_intel_bo *bo;
191 	struct import_race_thread_data t_data;
192 
193 	memset(&t_data, 0, sizeof(t_data));
194 	pthread_mutex_init(&t_data.mutex, NULL);
195 	t_data.prime_fd = -1;
196 
197 	igt_assert_eq(pthread_create(&t, NULL, import_close_thread , &t_data), 0);
198 
199 	igt_until_timeout(15) {
200 		bo = drm_intel_bo_alloc(bufmgr, "buf-shared", 4096, 4096);
201 		igt_assert(bo != NULL);
202 		/*
203 		 * We setup the test in such way, that create_from_* can race between
204 		 * unreference. If we're using prime, prime_fd is always a valid fd.
205 		 */
206 		if (use_flink)
207 			igt_assert_eq(drm_intel_bo_flink(bo, &(t_data.flink_name)), 0);
208 		else {
209 			pthread_mutex_lock(&t_data.mutex);
210 			igt_assert_eq(drm_intel_bo_gem_export_to_prime(bo, &(t_data.prime_fd)), 0);
211 			igt_assert_neq(t_data.prime_fd, -1);
212 			pthread_mutex_unlock(&t_data.mutex);
213 		}
214 
215 		drm_intel_bo_unreference(bo);
216 
217 		pthread_mutex_lock(&t_data.mutex);
218 		close(t_data.prime_fd);
219 		t_data.prime_fd = -1;
220 		pthread_mutex_unlock(&t_data.mutex);
221 	}
222 
223 	pthread_mutex_lock(&t_data.mutex);
224 	t_data.stop = 1;
225 	pthread_mutex_unlock(&t_data.mutex);
226 
227 	pthread_join(t, NULL);
228 	pthread_mutex_destroy(&t_data.mutex);
229 }
230 
231 pthread_t test_thread_id1;
232 pthread_t test_thread_id2;
233 pthread_t test_thread_id3;
234 pthread_t test_thread_id4;
235 
236 igt_main {
237 	igt_fixture {
238 		fd1 = drm_open_driver(DRIVER_INTEL);
239 		igt_assert(fd1 >= 0);
240 		bufmgr1 = drm_intel_bufmgr_gem_init(fd1, 8 *1024);
241 		igt_assert(bufmgr1);
242 
243 		drm_intel_bufmgr_gem_enable_reuse(bufmgr1);
244 
245 		fd = drm_open_driver(DRIVER_INTEL);
246 		igt_assert(fd >= 0);
247 		bufmgr = drm_intel_bufmgr_gem_init(fd, 8 *1024);
248 		igt_assert(bufmgr);
249 
250 		drm_intel_bufmgr_gem_enable_reuse(bufmgr);
251 	}
252 
253 	igt_subtest("import-close-race-flink") {
254 		use_flink = true;
255 		test_import_close_race();
256 	}
257 
258 	igt_subtest("import-close-race-prime") {
259 		use_flink = false;
260 		test_import_close_race();
261 	}
262 
263 	igt_subtest("flink") {
264 		use_flink = true;
265 
266 		pthread_create(&test_thread_id1, NULL, test_thread, NULL);
267 		pthread_create(&test_thread_id2, NULL, test_thread, NULL);
268 		pthread_create(&test_thread_id3, NULL, test_thread, NULL);
269 		pthread_create(&test_thread_id4, NULL, test_thread, NULL);
270 
271 		pthread_join(test_thread_id1, NULL);
272 		pthread_join(test_thread_id2, NULL);
273 		pthread_join(test_thread_id3, NULL);
274 		pthread_join(test_thread_id4, NULL);
275 	}
276 
277 	igt_subtest("prime") {
278 		use_flink = false;
279 
280 		pthread_create(&test_thread_id1, NULL, test_thread, NULL);
281 		pthread_create(&test_thread_id2, NULL, test_thread, NULL);
282 		pthread_create(&test_thread_id3, NULL, test_thread, NULL);
283 		pthread_create(&test_thread_id4, NULL, test_thread, NULL);
284 
285 		pthread_join(test_thread_id1, NULL);
286 		pthread_join(test_thread_id2, NULL);
287 		pthread_join(test_thread_id3, NULL);
288 		pthread_join(test_thread_id4, NULL);
289 	}
290 }
291