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, ¤t);
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