xref: /aosp_15_r20/external/igt-gpu-tools/tests/syncobj_wait.c (revision d83cc019efdc2edc6c4b16e9034a3ceb8d35d77c)
1 /*
2  * Copyright © 2017 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 
24 #include "igt.h"
25 #include "sw_sync.h"
26 #include "igt_syncobj.h"
27 #include <unistd.h>
28 #include <time.h>
29 #include <sys/ioctl.h>
30 #include <pthread.h>
31 #include <signal.h>
32 #include "drm.h"
33 #include <strings.h>
34 
35 IGT_TEST_DESCRIPTION("Tests for the drm sync object wait API");
36 
37 /* One tenth of a second */
38 #define SHORT_TIME_NSEC 100000000ull
39 
40 #define NSECS_PER_SEC 1000000000ull
41 
42 static uint64_t
gettime_ns(void)43 gettime_ns(void)
44 {
45 	struct timespec current;
46 	clock_gettime(CLOCK_MONOTONIC, &current);
47 	return (uint64_t)current.tv_sec * NSECS_PER_SEC + current.tv_nsec;
48 }
49 
50 static void
sleep_nsec(uint64_t time_nsec)51 sleep_nsec(uint64_t time_nsec)
52 {
53 	struct timespec t;
54 	t.tv_sec = time_nsec / NSECS_PER_SEC;
55 	t.tv_nsec = time_nsec % NSECS_PER_SEC;
56 	igt_assert_eq(nanosleep(&t, NULL), 0);
57 }
58 
59 static uint64_t
short_timeout(void)60 short_timeout(void)
61 {
62 	return gettime_ns() + SHORT_TIME_NSEC;
63 }
64 
65 static int
syncobj_attach_sw_sync(int fd,uint32_t handle)66 syncobj_attach_sw_sync(int fd, uint32_t handle)
67 {
68 	struct drm_syncobj_handle;
69 	int timeline, fence;
70 
71 	timeline = sw_sync_timeline_create();
72 	fence = sw_sync_timeline_create_fence(timeline, 1);
73 	syncobj_import_sync_file(fd, handle, fence);
74 	close(fence);
75 
76 	return timeline;
77 }
78 
79 static void
syncobj_trigger(int fd,uint32_t handle)80 syncobj_trigger(int fd, uint32_t handle)
81 {
82 	int timeline = syncobj_attach_sw_sync(fd, handle);
83 	sw_sync_timeline_inc(timeline, 1);
84 	close(timeline);
85 }
86 
87 static timer_t
set_timer(void (* cb)(union sigval),void * ptr,int i,uint64_t nsec)88 set_timer(void (*cb)(union sigval), void *ptr, int i, uint64_t nsec)
89 {
90         timer_t timer;
91         struct sigevent sev;
92         struct itimerspec its;
93 
94         memset(&sev, 0, sizeof(sev));
95         sev.sigev_notify = SIGEV_THREAD;
96 	if (ptr)
97 		sev.sigev_value.sival_ptr = ptr;
98 	else
99 		sev.sigev_value.sival_int = i;
100         sev.sigev_notify_function = cb;
101         igt_assert(timer_create(CLOCK_MONOTONIC, &sev, &timer) == 0);
102 
103         memset(&its, 0, sizeof(its));
104         its.it_value.tv_sec = nsec / NSEC_PER_SEC;
105         its.it_value.tv_nsec = nsec % NSEC_PER_SEC;
106         igt_assert(timer_settime(timer, 0, &its, NULL) == 0);
107 
108 	return timer;
109 }
110 
111 struct fd_handle_pair {
112 	int fd;
113 	uint32_t handle;
114 };
115 
116 static void
timeline_inc_func(union sigval sigval)117 timeline_inc_func(union sigval sigval)
118 {
119 	sw_sync_timeline_inc(sigval.sival_int, 1);
120 }
121 
122 static void
syncobj_trigger_free_pair_func(union sigval sigval)123 syncobj_trigger_free_pair_func(union sigval sigval)
124 {
125 	struct fd_handle_pair *pair = sigval.sival_ptr;
126 	syncobj_trigger(pair->fd, pair->handle);
127 	free(pair);
128 }
129 
130 static timer_t
syncobj_trigger_delayed(int fd,uint32_t syncobj,uint64_t nsec)131 syncobj_trigger_delayed(int fd, uint32_t syncobj, uint64_t nsec)
132 {
133 	struct fd_handle_pair *pair = malloc(sizeof(*pair));
134 
135 	pair->fd = fd;
136 	pair->handle = syncobj;
137 
138 	return set_timer(syncobj_trigger_free_pair_func, pair, 0, nsec);
139 }
140 
141 static void
test_wait_bad_flags(int fd)142 test_wait_bad_flags(int fd)
143 {
144 	struct local_syncobj_wait wait = { 0 };
145 	wait.flags = 0xdeadbeef;
146 	igt_assert_eq(__syncobj_wait(fd, &wait), -EINVAL);
147 }
148 
149 static void
test_wait_zero_handles(int fd)150 test_wait_zero_handles(int fd)
151 {
152 	struct local_syncobj_wait wait = { 0 };
153 	igt_assert_eq(__syncobj_wait(fd, &wait), -EINVAL);
154 }
155 
156 static void
test_wait_illegal_handle(int fd)157 test_wait_illegal_handle(int fd)
158 {
159 	struct local_syncobj_wait wait = { 0 };
160 	uint32_t handle = 0;
161 
162 	wait.count_handles = 1;
163 	wait.handles = to_user_pointer(&handle);
164 	igt_assert_eq(__syncobj_wait(fd, &wait), -ENOENT);
165 }
166 
167 static void
test_reset_zero_handles(int fd)168 test_reset_zero_handles(int fd)
169 {
170 	struct local_syncobj_array array = { 0 };
171 	int ret;
172 
173 	ret = drmIoctl(fd, LOCAL_IOCTL_SYNCOBJ_RESET, &array);
174 	igt_assert(ret == -1 && errno ==  EINVAL);
175 }
176 
177 static void
test_reset_illegal_handle(int fd)178 test_reset_illegal_handle(int fd)
179 {
180 	struct local_syncobj_array array = { 0 };
181 	uint32_t handle = 0;
182 	int ret;
183 
184 	array.count_handles = 1;
185 	array.handles = to_user_pointer(&handle);
186 	ret = drmIoctl(fd, LOCAL_IOCTL_SYNCOBJ_RESET, &array);
187 	igt_assert(ret == -1 && errno == ENOENT);
188 }
189 
190 static void
test_reset_one_illegal_handle(int fd)191 test_reset_one_illegal_handle(int fd)
192 {
193 	struct local_syncobj_array array = { 0 };
194 	uint32_t syncobjs[3];
195 	int ret;
196 
197 	syncobjs[0] = syncobj_create(fd, LOCAL_SYNCOBJ_CREATE_SIGNALED);
198 	syncobjs[1] = 0;
199 	syncobjs[2] = syncobj_create(fd, LOCAL_SYNCOBJ_CREATE_SIGNALED);
200 
201 	igt_assert_eq(syncobj_wait_err(fd, &syncobjs[0], 1, 0, 0), 0);
202 	igt_assert_eq(syncobj_wait_err(fd, &syncobjs[2], 1, 0, 0), 0);
203 
204 	array.count_handles = 3;
205 	array.handles = to_user_pointer(syncobjs);
206 	ret = drmIoctl(fd, LOCAL_IOCTL_SYNCOBJ_RESET, &array);
207 	igt_assert(ret == -1 && errno == ENOENT);
208 
209 	/* Assert that we didn't actually reset anything */
210 	igt_assert_eq(syncobj_wait_err(fd, &syncobjs[0], 1, 0, 0), 0);
211 	igt_assert_eq(syncobj_wait_err(fd, &syncobjs[2], 1, 0, 0), 0);
212 
213 	syncobj_destroy(fd, syncobjs[0]);
214 	syncobj_destroy(fd, syncobjs[2]);
215 }
216 
217 static void
test_reset_bad_pad(int fd)218 test_reset_bad_pad(int fd)
219 {
220 	struct local_syncobj_array array = { 0 };
221 	uint32_t handle = 0;
222 	int ret;
223 
224 	array.pad = 0xdeadbeef;
225 	array.count_handles = 1;
226 	array.handles = to_user_pointer(&handle);
227 	ret = drmIoctl(fd, LOCAL_IOCTL_SYNCOBJ_RESET, &array);
228 	igt_assert(ret == -1 && errno == EINVAL);
229 }
230 
231 static void
test_signal_zero_handles(int fd)232 test_signal_zero_handles(int fd)
233 {
234 	struct local_syncobj_array array = { 0 };
235 	int ret;
236 
237 	ret = drmIoctl(fd, LOCAL_IOCTL_SYNCOBJ_SIGNAL, &array);
238 	igt_assert(ret == -1 && errno == EINVAL);
239 }
240 
241 static void
test_signal_illegal_handle(int fd)242 test_signal_illegal_handle(int fd)
243 {
244 	struct local_syncobj_array array = { 0 };
245 	uint32_t handle = 0;
246 	int ret;
247 
248 	array.count_handles = 1;
249 	array.handles = to_user_pointer(&handle);
250 	ret = drmIoctl(fd, LOCAL_IOCTL_SYNCOBJ_SIGNAL, &array);
251 	igt_assert(ret == -1 && errno == ENOENT);
252 }
253 
254 static void
test_signal_one_illegal_handle(int fd)255 test_signal_one_illegal_handle(int fd)
256 {
257 	struct local_syncobj_array array = { 0 };
258 	uint32_t syncobjs[3];
259 	int ret;
260 
261 	syncobjs[0] = syncobj_create(fd, 0);
262 	syncobjs[1] = 0;
263 	syncobjs[2] = syncobj_create(fd, 0);
264 
265 	igt_assert_eq(syncobj_wait_err(fd, &syncobjs[0], 1, 0, 0), -EINVAL);
266 	igt_assert_eq(syncobj_wait_err(fd, &syncobjs[2], 1, 0, 0), -EINVAL);
267 
268 	array.count_handles = 3;
269 	array.handles = to_user_pointer(syncobjs);
270 	ret = drmIoctl(fd, LOCAL_IOCTL_SYNCOBJ_SIGNAL, &array);
271 	igt_assert(ret == -1 && errno == ENOENT);
272 
273 	/* Assert that we didn't actually reset anything */
274 	igt_assert_eq(syncobj_wait_err(fd, &syncobjs[0], 1, 0, 0), -EINVAL);
275 	igt_assert_eq(syncobj_wait_err(fd, &syncobjs[2], 1, 0, 0), -EINVAL);
276 
277 	syncobj_destroy(fd, syncobjs[0]);
278 	syncobj_destroy(fd, syncobjs[2]);
279 }
280 
281 static void
test_signal_bad_pad(int fd)282 test_signal_bad_pad(int fd)
283 {
284 	struct local_syncobj_array array = { 0 };
285 	uint32_t handle = 0;
286 	int ret;
287 
288 	array.pad = 0xdeadbeef;
289 	array.count_handles = 1;
290 	array.handles = to_user_pointer(&handle);
291 	ret = drmIoctl(fd, LOCAL_IOCTL_SYNCOBJ_SIGNAL, &array);
292 	igt_assert(ret == -1 && errno ==  EINVAL);
293 }
294 
295 #define WAIT_FOR_SUBMIT		(1 << 0)
296 #define WAIT_ALL		(1 << 1)
297 #define WAIT_UNSUBMITTED	(1 << 2)
298 #define WAIT_SUBMITTED		(1 << 3)
299 #define WAIT_SIGNALED		(1 << 4)
300 #define WAIT_FLAGS_MAX		(1 << 5) - 1
301 
302 static uint32_t
flags_for_test_flags(uint32_t test_flags)303 flags_for_test_flags(uint32_t test_flags)
304 {
305 	uint32_t flags = 0;
306 
307 	if (test_flags & WAIT_FOR_SUBMIT)
308 		flags |= LOCAL_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT;
309 
310 	if (test_flags & WAIT_ALL)
311 		flags |= LOCAL_SYNCOBJ_WAIT_FLAGS_WAIT_ALL;
312 
313 	return flags;
314 }
315 
316 static void
test_single_wait(int fd,uint32_t test_flags,int expect)317 test_single_wait(int fd, uint32_t test_flags, int expect)
318 {
319 	uint32_t syncobj = syncobj_create(fd, 0);
320 	uint32_t flags = flags_for_test_flags(test_flags);
321 	int timeline = -1;
322 
323 	if (test_flags & (WAIT_SUBMITTED | WAIT_SIGNALED))
324 		timeline = syncobj_attach_sw_sync(fd, syncobj);
325 
326 	if (test_flags & WAIT_SIGNALED)
327 		sw_sync_timeline_inc(timeline, 1);
328 
329 	igt_assert_eq(syncobj_wait_err(fd, &syncobj, 1, 0, flags), expect);
330 
331 	igt_assert_eq(syncobj_wait_err(fd, &syncobj, 1, short_timeout(),
332 				       flags), expect);
333 
334 	if (expect != -ETIME) {
335 		igt_assert_eq(syncobj_wait_err(fd, &syncobj, 1, UINT64_MAX,
336 					       flags), expect);
337 	}
338 
339 	syncobj_destroy(fd, syncobj);
340 	if (timeline != -1)
341 		close(timeline);
342 }
343 
344 static void
test_wait_delayed_signal(int fd,uint32_t test_flags)345 test_wait_delayed_signal(int fd, uint32_t test_flags)
346 {
347 	uint32_t syncobj = syncobj_create(fd, 0);
348 	uint32_t flags = flags_for_test_flags(test_flags);
349 	int timeline = -1;
350 	timer_t timer;
351 
352 	if (test_flags & WAIT_FOR_SUBMIT) {
353 		timer = syncobj_trigger_delayed(fd, syncobj, SHORT_TIME_NSEC);
354 	} else {
355 		timeline = syncobj_attach_sw_sync(fd, syncobj);
356 		timer = set_timer(timeline_inc_func, NULL,
357 				  timeline, SHORT_TIME_NSEC);
358 	}
359 
360 	igt_assert(syncobj_wait(fd, &syncobj, 1,
361 				gettime_ns() + SHORT_TIME_NSEC * 2,
362 				flags, NULL));
363 
364 	timer_delete(timer);
365 
366 	if (timeline != -1)
367 		close(timeline);
368 
369 	syncobj_destroy(fd, syncobj);
370 }
371 
372 static void
test_reset_unsignaled(int fd)373 test_reset_unsignaled(int fd)
374 {
375 	uint32_t syncobj = syncobj_create(fd, 0);
376 
377 	igt_assert_eq(syncobj_wait_err(fd, &syncobj, 1, 0, 0), -EINVAL);
378 
379 	syncobj_reset(fd, &syncobj, 1);
380 
381 	igt_assert_eq(syncobj_wait_err(fd, &syncobj, 1, 0, 0), -EINVAL);
382 
383 	syncobj_destroy(fd, syncobj);
384 }
385 
386 static void
test_reset_signaled(int fd)387 test_reset_signaled(int fd)
388 {
389 	uint32_t syncobj = syncobj_create(fd, 0);
390 
391 	syncobj_trigger(fd, syncobj);
392 
393 	igt_assert_eq(syncobj_wait_err(fd, &syncobj, 1, 0, 0), 0);
394 
395 	syncobj_reset(fd, &syncobj, 1);
396 
397 	igt_assert_eq(syncobj_wait_err(fd, &syncobj, 1, 0, 0), -EINVAL);
398 
399 	syncobj_destroy(fd, syncobj);
400 }
401 
402 static void
test_reset_multiple_signaled(int fd)403 test_reset_multiple_signaled(int fd)
404 {
405 	uint32_t syncobjs[3];
406 	int i;
407 
408 	for (i = 0; i < 3; i++) {
409 		syncobjs[i] = syncobj_create(fd, 0);
410 		syncobj_trigger(fd, syncobjs[i]);
411 	}
412 
413 	igt_assert_eq(syncobj_wait_err(fd, syncobjs, 3, 0, 0), 0);
414 
415 	syncobj_reset(fd, syncobjs, 3);
416 
417 	for (i = 0; i < 3; i++) {
418 		igt_assert_eq(syncobj_wait_err(fd, &syncobjs[i], 1,
419 					       0, 0), -EINVAL);
420 		syncobj_destroy(fd, syncobjs[i]);
421 	}
422 }
423 
424 static void
reset_and_trigger_func(union sigval sigval)425 reset_and_trigger_func(union sigval sigval)
426 {
427 	struct fd_handle_pair *pair = sigval.sival_ptr;
428 	syncobj_reset(pair->fd, &pair->handle, 1);
429 	syncobj_trigger(pair->fd, pair->handle);
430 }
431 
432 static void
test_reset_during_wait_for_submit(int fd)433 test_reset_during_wait_for_submit(int fd)
434 {
435 	uint32_t syncobj = syncobj_create(fd, 0);
436 	uint32_t flags = LOCAL_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT;
437 	struct fd_handle_pair pair;
438 	timer_t timer;
439 
440 	pair.fd = fd;
441 	pair.handle = syncobj;
442 	timer = set_timer(reset_and_trigger_func, &pair, 0, SHORT_TIME_NSEC);
443 
444 	/* A reset should be a no-op even if we're in the middle of a wait */
445 	igt_assert(syncobj_wait(fd, &syncobj, 1,
446 				gettime_ns() + SHORT_TIME_NSEC * 2,
447 				flags, NULL));
448 
449 	timer_delete(timer);
450 
451 	syncobj_destroy(fd, syncobj);
452 }
453 
454 static void
test_signal(int fd)455 test_signal(int fd)
456 {
457 	uint32_t syncobj = syncobj_create(fd, 0);
458 	uint32_t flags = LOCAL_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT;
459 
460 	igt_assert_eq(syncobj_wait_err(fd, &syncobj, 1, 0, 0), -EINVAL);
461 	igt_assert_eq(syncobj_wait_err(fd, &syncobj, 1, 0, flags), -ETIME);
462 
463 	syncobj_signal(fd, &syncobj, 1);
464 
465 	igt_assert(syncobj_wait(fd, &syncobj, 1, 0, 0, NULL));
466 	igt_assert(syncobj_wait(fd, &syncobj, 1, 0, flags, NULL));
467 
468 	syncobj_destroy(fd, syncobj);
469 }
470 
471 static void
test_multi_wait(int fd,uint32_t test_flags,int expect)472 test_multi_wait(int fd, uint32_t test_flags, int expect)
473 {
474 	uint32_t syncobjs[3];
475 	uint32_t tflag, flags;
476 	int i, fidx, timeline;
477 
478 	syncobjs[0] = syncobj_create(fd, 0);
479 	syncobjs[1] = syncobj_create(fd, 0);
480 	syncobjs[2] = syncobj_create(fd, 0);
481 
482 	flags = flags_for_test_flags(test_flags);
483 	test_flags &= ~(WAIT_ALL | WAIT_FOR_SUBMIT);
484 
485 	for (i = 0; i < 3; i++) {
486 		fidx = ffs(test_flags) - 1;
487 		tflag = (1 << fidx);
488 
489 		if (test_flags & ~tflag)
490 			test_flags &= ~tflag;
491 
492 		if (tflag & (WAIT_SUBMITTED | WAIT_SIGNALED))
493 			timeline = syncobj_attach_sw_sync(fd, syncobjs[i]);
494 		if (tflag & WAIT_SIGNALED)
495 			sw_sync_timeline_inc(timeline, 1);
496 	}
497 
498 	igt_assert_eq(syncobj_wait_err(fd, syncobjs, 3, 0, flags), expect);
499 
500 	igt_assert_eq(syncobj_wait_err(fd, syncobjs, 3, short_timeout(),
501 				       flags), expect);
502 
503 	if (expect != -ETIME) {
504 		igt_assert_eq(syncobj_wait_err(fd, syncobjs, 3, UINT64_MAX,
505 					       flags), expect);
506 	}
507 
508 	syncobj_destroy(fd, syncobjs[0]);
509 	syncobj_destroy(fd, syncobjs[1]);
510 	syncobj_destroy(fd, syncobjs[2]);
511 }
512 
513 struct wait_thread_data {
514 	int fd;
515 	struct local_syncobj_wait wait;
516 };
517 
518 static void *
wait_thread_func(void * data)519 wait_thread_func(void *data)
520 {
521 	struct wait_thread_data *wait = data;
522 	igt_assert_eq(__syncobj_wait(wait->fd, &wait->wait), 0);
523 	return NULL;
524 }
525 
526 static void
test_wait_snapshot(int fd,uint32_t test_flags)527 test_wait_snapshot(int fd, uint32_t test_flags)
528 {
529 	struct wait_thread_data wait = { 0 };
530 	uint32_t syncobjs[2];
531 	int timelines[3] = { -1, -1, -1 };
532 	pthread_t thread;
533 
534 	syncobjs[0] = syncobj_create(fd, 0);
535 	syncobjs[1] = syncobj_create(fd, 0);
536 
537 	if (!(test_flags & WAIT_FOR_SUBMIT)) {
538 		timelines[0] = syncobj_attach_sw_sync(fd, syncobjs[0]);
539 		timelines[1] = syncobj_attach_sw_sync(fd, syncobjs[1]);
540 	}
541 
542 	wait.fd = fd;
543 	wait.wait.handles = to_user_pointer(syncobjs);
544 	wait.wait.count_handles = 2;
545 	wait.wait.timeout_nsec = short_timeout();
546 	wait.wait.flags = flags_for_test_flags(test_flags);
547 
548 	igt_assert_eq(pthread_create(&thread, NULL, wait_thread_func, &wait), 0);
549 
550 	sleep_nsec(SHORT_TIME_NSEC / 5);
551 
552 	/* Try to fake the kernel out by triggering or partially triggering
553 	 * the first fence.
554 	 */
555 	if (test_flags & WAIT_ALL) {
556 		/* If it's WAIT_ALL, actually trigger it */
557 		if (timelines[0] == -1)
558 			syncobj_trigger(fd, syncobjs[0]);
559 		else
560 			sw_sync_timeline_inc(timelines[0], 1);
561 	} else if (test_flags & WAIT_FOR_SUBMIT) {
562 		timelines[0] = syncobj_attach_sw_sync(fd, syncobjs[0]);
563 	}
564 
565 	sleep_nsec(SHORT_TIME_NSEC / 5);
566 
567 	/* Then reset it */
568 	syncobj_reset(fd, &syncobjs[0], 1);
569 
570 	sleep_nsec(SHORT_TIME_NSEC / 5);
571 
572 	/* Then "submit" it in a way that will never trigger.  This way, if
573 	 * the kernel picks up on the new fence (it shouldn't), we'll get a
574 	 * timeout.
575 	 */
576 	timelines[2] = syncobj_attach_sw_sync(fd, syncobjs[0]);
577 
578 	sleep_nsec(SHORT_TIME_NSEC / 5);
579 
580 	/* Now trigger the second fence to complete the wait */
581 
582 	if (timelines[1] == -1)
583 		syncobj_trigger(fd, syncobjs[1]);
584 	else
585 		sw_sync_timeline_inc(timelines[1], 1);
586 
587 	pthread_join(thread, NULL);
588 
589 	if (!(test_flags & WAIT_ALL))
590 		igt_assert_eq(wait.wait.first_signaled, 1);
591 
592 	close(timelines[0]);
593 	close(timelines[1]);
594 	close(timelines[2]);
595 	syncobj_destroy(fd, syncobjs[0]);
596 	syncobj_destroy(fd, syncobjs[1]);
597 }
598 
599 /* The numbers 0-7, each repeated 5x and shuffled. */
600 static const unsigned shuffled_0_7_x4[] = {
601 	2, 0, 6, 1, 1, 4, 5, 2, 0, 7, 1, 7, 6, 3, 4, 5,
602 	0, 2, 7, 3, 5, 4, 0, 6, 7, 3, 2, 5, 6, 1, 4, 3,
603 };
604 
605 enum syncobj_stage {
606 	STAGE_UNSUBMITTED,
607 	STAGE_SUBMITTED,
608 	STAGE_SIGNALED,
609 	STAGE_RESET,
610 	STAGE_RESUBMITTED,
611 };
612 
613 static void
test_wait_complex(int fd,uint32_t test_flags)614 test_wait_complex(int fd, uint32_t test_flags)
615 {
616 	struct wait_thread_data wait = { 0 };
617 	uint32_t syncobjs[8];
618 	enum syncobj_stage stage[8];
619 	int i, j, timelines[8];
620 	uint32_t first_signaled = -1, num_signaled = 0;
621 	pthread_t thread;
622 
623 	for (i = 0; i < 8; i++) {
624 		stage[i] = STAGE_UNSUBMITTED;
625 		syncobjs[i] = syncobj_create(fd, 0);
626 	}
627 
628 	if (test_flags & WAIT_FOR_SUBMIT) {
629 		for (i = 0; i < 8; i++)
630 			timelines[i] = -1;
631 	} else {
632 		for (i = 0; i < 8; i++)
633 			timelines[i] = syncobj_attach_sw_sync(fd, syncobjs[i]);
634 	}
635 
636 	wait.fd = fd;
637 	wait.wait.handles = to_user_pointer(syncobjs);
638 	wait.wait.count_handles = 2;
639 	wait.wait.timeout_nsec = gettime_ns() + NSECS_PER_SEC;
640 	wait.wait.flags = flags_for_test_flags(test_flags);
641 
642 	igt_assert_eq(pthread_create(&thread, NULL, wait_thread_func, &wait), 0);
643 
644 	sleep_nsec(NSECS_PER_SEC / 50);
645 
646 	num_signaled = 0;
647 	for (j = 0; j < ARRAY_SIZE(shuffled_0_7_x4); j++) {
648 		i = shuffled_0_7_x4[j];
649 		igt_assert_lt(i, ARRAY_SIZE(syncobjs));
650 
651 		switch (stage[i]++) {
652 		case STAGE_UNSUBMITTED:
653 			/* We need to submit attach a fence */
654 			if (!(test_flags & WAIT_FOR_SUBMIT)) {
655 				/* We had to attach one up-front */
656 				igt_assert_neq(timelines[i], -1);
657 				break;
658 			}
659 			timelines[i] = syncobj_attach_sw_sync(fd, syncobjs[i]);
660 			break;
661 
662 		case STAGE_SUBMITTED:
663 			/* We have a fence, trigger it */
664 			igt_assert_neq(timelines[i], -1);
665 			sw_sync_timeline_inc(timelines[i], 1);
666 			close(timelines[i]);
667 			timelines[i] = -1;
668 			if (num_signaled == 0)
669 				first_signaled = i;
670 			num_signaled++;
671 			break;
672 
673 		case STAGE_SIGNALED:
674 			/* We're already signaled, reset */
675 			syncobj_reset(fd, &syncobjs[i], 1);
676 			break;
677 
678 		case STAGE_RESET:
679 			/* We're reset, submit and don't signal */
680 			timelines[i] = syncobj_attach_sw_sync(fd, syncobjs[i]);
681 			break;
682 
683 		case STAGE_RESUBMITTED:
684 			igt_assert(!"Should not reach this stage");
685 			break;
686 		}
687 
688 		if (test_flags & WAIT_ALL) {
689 			if (num_signaled == ARRAY_SIZE(syncobjs))
690 				break;
691 		} else {
692 			if (num_signaled > 0)
693 				break;
694 		}
695 
696 		sleep_nsec(NSECS_PER_SEC / 100);
697 	}
698 
699 	pthread_join(thread, NULL);
700 
701 	if (test_flags & WAIT_ALL) {
702 		igt_assert_eq(num_signaled, ARRAY_SIZE(syncobjs));
703 	} else {
704 		igt_assert_eq(num_signaled, 1);
705 		igt_assert_eq(wait.wait.first_signaled, first_signaled);
706 	}
707 
708 	for (i = 0; i < 8; i++) {
709 		close(timelines[i]);
710 		syncobj_destroy(fd, syncobjs[i]);
711 	}
712 }
713 
714 static void
test_wait_interrupted(int fd,uint32_t test_flags)715 test_wait_interrupted(int fd, uint32_t test_flags)
716 {
717 	struct local_syncobj_wait wait = { 0 };
718 	uint32_t syncobj = syncobj_create(fd, 0);
719 	int timeline;
720 
721 	wait.handles = to_user_pointer(&syncobj);
722 	wait.count_handles = 1;
723 	wait.flags = flags_for_test_flags(test_flags);
724 
725 	if (test_flags & WAIT_FOR_SUBMIT) {
726 		wait.timeout_nsec = short_timeout();
727 		igt_while_interruptible(true)
728 			igt_assert_eq(__syncobj_wait(fd, &wait), -ETIME);
729 	}
730 
731 	timeline = syncobj_attach_sw_sync(fd, syncobj);
732 
733 	wait.timeout_nsec = short_timeout();
734 	igt_while_interruptible(true)
735 		igt_assert_eq(__syncobj_wait(fd, &wait), -ETIME);
736 
737 	syncobj_destroy(fd, syncobj);
738 	close(timeline);
739 }
740 
741 static bool
has_syncobj_wait(int fd)742 has_syncobj_wait(int fd)
743 {
744 	struct local_syncobj_wait wait = { 0 };
745 	uint32_t handle = 0;
746 	uint64_t value;
747 	int ret;
748 
749 	if (drmGetCap(fd, DRM_CAP_SYNCOBJ, &value))
750 		return false;
751 	if (!value)
752 		return false;
753 
754 	/* Try waiting for zero sync objects should fail with EINVAL */
755 	wait.count_handles = 1;
756 	wait.handles = to_user_pointer(&handle);
757 	ret = drmIoctl(fd, LOCAL_IOCTL_SYNCOBJ_WAIT, &wait);
758 	return ret == -1 && errno == ENOENT;
759 }
760 
761 igt_main
762 {
763 	int fd = -1;
764 
765 	igt_fixture {
766 		fd = drm_open_driver(DRIVER_ANY);
767 		igt_require(has_syncobj_wait(fd));
768 		igt_require_sw_sync();
769 	}
770 
771 	igt_subtest("invalid-wait-bad-flags")
772 		test_wait_bad_flags(fd);
773 
774 	igt_subtest("invalid-wait-zero-handles")
775 		test_wait_zero_handles(fd);
776 
777 	igt_subtest("invalid-wait-illegal-handle")
778 		test_wait_illegal_handle(fd);
779 
780 	igt_subtest("invalid-reset-zero-handles")
781 		test_reset_zero_handles(fd);
782 
783 	igt_subtest("invalid-reset-illegal-handle")
784 		test_reset_illegal_handle(fd);
785 
786 	igt_subtest("invalid-reset-one-illegal-handle")
787 		test_reset_one_illegal_handle(fd);
788 
789 	igt_subtest("invalid-reset-bad-pad")
790 		test_reset_bad_pad(fd);
791 
792 	igt_subtest("invalid-signal-zero-handles")
793 		test_signal_zero_handles(fd);
794 
795 	igt_subtest("invalid-signal-illegal-handle")
796 		test_signal_illegal_handle(fd);
797 
798 	igt_subtest("invalid-signal-one-illegal-handle")
799 		test_signal_one_illegal_handle(fd);
800 
801 	igt_subtest("invalid-signal-bad-pad")
802 		test_signal_bad_pad(fd);
803 
804 	for (unsigned flags = 0; flags < WAIT_FLAGS_MAX; flags++) {
805 		int err;
806 
807 		/* Only one wait mode for single-wait tests */
808 		if (__builtin_popcount(flags & (WAIT_UNSUBMITTED |
809 						WAIT_SUBMITTED |
810 						WAIT_SIGNALED)) != 1)
811 			continue;
812 
813 		if ((flags & WAIT_UNSUBMITTED) && !(flags & WAIT_FOR_SUBMIT))
814 			err = -EINVAL;
815 		else if (!(flags & WAIT_SIGNALED))
816 			err = -ETIME;
817 		else
818 			err = 0;
819 
820 		igt_subtest_f("%ssingle-wait%s%s%s%s%s",
821 			      err == -EINVAL ? "invalid-" : "",
822 			      (flags & WAIT_ALL) ? "-all" : "",
823 			      (flags & WAIT_FOR_SUBMIT) ? "-for-submit" : "",
824 			      (flags & WAIT_UNSUBMITTED) ? "-unsubmitted" : "",
825 			      (flags & WAIT_SUBMITTED) ? "-submitted" : "",
826 			      (flags & WAIT_SIGNALED) ? "-signaled" : "")
827 			test_single_wait(fd, flags, err);
828 	}
829 
830 	igt_subtest("wait-delayed-signal")
831 		test_wait_delayed_signal(fd, 0);
832 
833 	igt_subtest("wait-for-submit-delayed-submit")
834 		test_wait_delayed_signal(fd, WAIT_FOR_SUBMIT);
835 
836 	igt_subtest("wait-all-delayed-signal")
837 		test_wait_delayed_signal(fd, WAIT_ALL);
838 
839 	igt_subtest("wait-all-for-submit-delayed-submit")
840 		test_wait_delayed_signal(fd, WAIT_ALL | WAIT_FOR_SUBMIT);
841 
842 	igt_subtest("reset-unsignaled")
843 		test_reset_unsignaled(fd);
844 
845 	igt_subtest("reset-signaled")
846 		test_reset_signaled(fd);
847 
848 	igt_subtest("reset-multiple-signaled")
849 		test_reset_multiple_signaled(fd);
850 
851 	igt_subtest("reset-during-wait-for-submit")
852 		test_reset_during_wait_for_submit(fd);
853 
854 	igt_subtest("signal")
855 		test_signal(fd);
856 
857 	for (unsigned flags = 0; flags < WAIT_FLAGS_MAX; flags++) {
858 		int err;
859 
860 		/* At least one wait mode for multi-wait tests */
861 		if (!(flags & (WAIT_UNSUBMITTED |
862 			       WAIT_SUBMITTED |
863 			       WAIT_SIGNALED)))
864 			continue;
865 
866 		err = 0;
867 		if ((flags & WAIT_UNSUBMITTED) && !(flags & WAIT_FOR_SUBMIT)) {
868 			err = -EINVAL;
869 		} else if (flags & WAIT_ALL) {
870 			if (flags & (WAIT_UNSUBMITTED | WAIT_SUBMITTED))
871 				err = -ETIME;
872 		} else {
873 			if (!(flags & WAIT_SIGNALED))
874 				err = -ETIME;
875 		}
876 
877 		igt_subtest_f("%smulti-wait%s%s%s%s%s",
878 			      err == -EINVAL ? "invalid-" : "",
879 			      (flags & WAIT_ALL) ? "-all" : "",
880 			      (flags & WAIT_FOR_SUBMIT) ? "-for-submit" : "",
881 			      (flags & WAIT_UNSUBMITTED) ? "-unsubmitted" : "",
882 			      (flags & WAIT_SUBMITTED) ? "-submitted" : "",
883 			      (flags & WAIT_SIGNALED) ? "-signaled" : "")
884 			test_multi_wait(fd, flags, err);
885 	}
886 
887 	igt_subtest("wait-any-snapshot")
888 		test_wait_snapshot(fd, 0);
889 
890 	igt_subtest("wait-all-snapshot")
891 		test_wait_snapshot(fd, WAIT_ALL);
892 
893 	igt_subtest("wait-for-submit-snapshot")
894 		test_wait_snapshot(fd, WAIT_FOR_SUBMIT);
895 
896 	igt_subtest("wait-all-for-submit-snapshot")
897 		test_wait_snapshot(fd, WAIT_ALL | WAIT_FOR_SUBMIT);
898 
899 	igt_subtest("wait-any-complex")
900 		test_wait_complex(fd, 0);
901 
902 	igt_subtest("wait-all-complex")
903 		test_wait_complex(fd, WAIT_ALL);
904 
905 	igt_subtest("wait-for-submit-complex")
906 		test_wait_complex(fd, WAIT_FOR_SUBMIT);
907 
908 	igt_subtest("wait-all-for-submit-complex")
909 		test_wait_complex(fd, WAIT_ALL | WAIT_FOR_SUBMIT);
910 
911 	igt_subtest("wait-any-interrupted")
912 		test_wait_interrupted(fd, 0);
913 
914 	igt_subtest("wait-all-interrupted")
915 		test_wait_interrupted(fd, WAIT_ALL);
916 }
917