1 /*
2 * Copyright © 2016 Collabora, Ltd.
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 * Robert Foss <[email protected]>
25 */
26
27 #include <pthread.h>
28 #include <semaphore.h>
29 #include <stdatomic.h>
30 #include <stdint.h>
31 #include <sys/socket.h>
32 #include <sys/types.h>
33 #include <unistd.h>
34
35 #include "igt.h"
36 #include "igt_aux.h"
37 #include "igt_primes.h"
38
39 #include "sw_sync.h"
40
41
42 IGT_TEST_DESCRIPTION("Test SW Sync Framework");
43
44 typedef struct {
45 int timeline;
46 uint32_t thread_id;
47 _Atomic(uint32_t) *counter;
48 sem_t *sem;
49 } data_t;
50
test_alloc_timeline(void)51 static void test_alloc_timeline(void)
52 {
53 int timeline;
54
55 timeline = sw_sync_timeline_create();
56 close(timeline);
57 }
58
test_alloc_fence(void)59 static void test_alloc_fence(void)
60 {
61 int in_fence;
62 int timeline;
63
64 timeline = sw_sync_timeline_create();
65 in_fence = sw_sync_timeline_create_fence(timeline, 0);
66
67 close(in_fence);
68 close(timeline);
69 }
70
test_alloc_fence_invalid_timeline(void)71 static void test_alloc_fence_invalid_timeline(void)
72 {
73 igt_assert_f(__sw_sync_timeline_create_fence(-1, 0) < 0,
74 "Did not fail to create fence on invalid timeline\n");
75 }
76
test_timeline_closed(void)77 static void test_timeline_closed(void)
78 {
79 int fence;
80 int timeline;
81
82 timeline = sw_sync_timeline_create();
83 fence = sw_sync_timeline_create_fence(timeline, 1);
84
85 close(timeline);
86 igt_assert_f(sync_fence_wait(fence, 0) == 0,
87 "Failure waiting on unsignaled fence on closed timeline\n");
88 igt_assert_f(sync_fence_status(fence) == -ENOENT,
89 "Failure in marking up an unsignaled fence on closed timeline\n");
90 }
91
test_timeline_closed_signaled(void)92 static void test_timeline_closed_signaled(void)
93 {
94 int fence;
95 int timeline;
96
97 timeline = sw_sync_timeline_create();
98 fence = sw_sync_timeline_create_fence(timeline, 1);
99
100 sw_sync_timeline_inc(timeline, 1);
101 close(timeline);
102 igt_assert_f(sync_fence_wait(fence, 0) == 0,
103 "Failure waiting on signaled fence for closed timeline\n");
104 }
105
test_alloc_merge_fence(void)106 static void test_alloc_merge_fence(void)
107 {
108 int in_fence[2];
109 int fence_merge;
110 int timeline[2];
111
112 timeline[0] = sw_sync_timeline_create();
113 timeline[1] = sw_sync_timeline_create();
114
115 in_fence[0] = sw_sync_timeline_create_fence(timeline[0], 1);
116 in_fence[1] = sw_sync_timeline_create_fence(timeline[1], 1);
117 fence_merge = sync_fence_merge(in_fence[1], in_fence[0]);
118
119 close(in_fence[0]);
120 close(in_fence[1]);
121 close(fence_merge);
122 close(timeline[0]);
123 close(timeline[1]);
124 }
125
test_sync_busy(void)126 static void test_sync_busy(void)
127 {
128 int fence;
129 int timeline;
130 int seqno;
131
132 timeline = sw_sync_timeline_create();
133 fence = sw_sync_timeline_create_fence(timeline, 5);
134
135 /* Make sure that fence has not been signaled yet */
136 igt_assert_f(sync_fence_wait(fence, 0) == -ETIME,
137 "Fence signaled early (timeline value 0, fence seqno 5)\n");
138
139 /* Advance timeline from 0 -> 1 */
140 sw_sync_timeline_inc(timeline, 1);
141
142 /* Make sure that fence has not been signaled yet */
143 igt_assert_f(sync_fence_wait(fence, 0) == -ETIME,
144 "Fence signaled early (timeline value 1, fence seqno 5)\n");
145
146 /* Advance timeline from 1 -> 5: signaling the fence (seqno 5)*/
147 sw_sync_timeline_inc(timeline, 4);
148 igt_assert_f(sync_fence_wait(fence, 0) == 0,
149 "Fence not signaled (timeline value 5, fence seqno 5)\n");
150
151 /* Go even further, and confirm wait still succeeds */
152 sw_sync_timeline_inc(timeline, 5);
153 igt_assert_f(sync_fence_wait(fence, 0) == 0,
154 "Fence not signaled (timeline value 10, fence seqno 5)\n");
155
156 seqno = 10;
157 for_each_prime_number(prime, 100) {
158 int fence_prime;
159 seqno += prime;
160
161 fence_prime = sw_sync_timeline_create_fence(timeline, seqno);
162 sw_sync_timeline_inc(timeline, prime);
163
164 igt_assert_f(sync_fence_wait(fence_prime, 0) == 0,
165 "Fence not signaled during test of prime timeline increments\n");
166 close(fence_prime);
167 }
168
169 close(fence);
170 close(timeline);
171 }
172
test_sync_busy_fork_unixsocket(void)173 static void test_sync_busy_fork_unixsocket(void)
174 {
175 int fence;
176 int timeline;
177 int sv[2];
178
179 igt_require(socketpair(AF_UNIX, SOCK_DGRAM, 0, sv) == 0);
180
181 timeline = sw_sync_timeline_create();
182 fence = sw_sync_timeline_create_fence(timeline, 1);
183
184 igt_fork(child, 1) {
185 /* Child process */
186 int socket = sv[1];
187 int socket_timeline;
188 struct msghdr msg = {0};
189 struct cmsghdr *cmsg;
190 unsigned char *data;
191 char m_buffer[256];
192 char c_buffer[256];
193 struct iovec io = { .iov_base = m_buffer, .iov_len = sizeof(m_buffer) };
194 close(sv[0]);
195
196 msg.msg_iov = &io;
197 msg.msg_iovlen = 1;
198 msg.msg_control = c_buffer;
199 msg.msg_controllen = sizeof(c_buffer);
200
201 igt_assert(recvmsg(socket, &msg, 0) > 0);
202
203 cmsg = CMSG_FIRSTHDR(&msg);
204 data = CMSG_DATA(cmsg);
205 socket_timeline = *((int *) data);
206
207 /* Advance timeline from 0 -> 1 */
208 sw_sync_timeline_inc(socket_timeline, 1);
209 }
210
211 {
212 /* Parent process */
213 int socket = sv[0];
214 struct cmsghdr *cmsg;
215 struct iovec io = { .iov_base = (char *)"ABC", .iov_len = 3 };
216 struct msghdr msg = { 0 };
217 char buf[CMSG_SPACE(sizeof(timeline))];
218 memset(buf, '\0', sizeof(buf));
219 close(sv[1]);
220
221 msg.msg_iov = &io;
222 msg.msg_iovlen = 1;
223 msg.msg_control = buf;
224 msg.msg_controllen = sizeof(buf);
225
226 cmsg = CMSG_FIRSTHDR(&msg);
227 cmsg->cmsg_level = SOL_SOCKET;
228 cmsg->cmsg_type = SCM_RIGHTS;
229 cmsg->cmsg_len = CMSG_LEN(sizeof(timeline));
230
231 *((int *) CMSG_DATA(cmsg)) = timeline;
232 msg.msg_controllen = cmsg->cmsg_len;
233
234 igt_assert_f(sync_fence_wait(fence, 0) == -ETIME,
235 "Fence signaled (it should not have been signalled yet)\n");
236
237 igt_assert(sendmsg(socket, &msg, 0) > 0);
238
239 igt_assert_f(sync_fence_wait(fence, 2*1000) == 0,
240 "Fence not signaled (timeline value 1 fence seqno 1)\n");
241 }
242
243 igt_waitchildren();
244
245 close(fence);
246 close(timeline);
247 }
248
test_sync_busy_fork(void)249 static void test_sync_busy_fork(void)
250 {
251 int timeline = sw_sync_timeline_create();
252 int fence = sw_sync_timeline_create_fence(timeline, 1);
253
254 igt_assert_f(sync_fence_wait(fence, 0) == -ETIME,
255 "Fence signaled (it should not have been signalled yet)\n");
256
257 igt_fork(child, 1) {
258 usleep(1*1000*1000);
259 /* Advance timeline from 0 -> 1 */
260 sw_sync_timeline_inc(timeline, 1);
261 }
262
263 igt_assert_f(sync_fence_wait(fence, 2*1000) == 0,
264 "Fence not signaled (timeline value 1 fence seqno 1)\n");
265
266 igt_waitchildren();
267
268 close(fence);
269 close(timeline);
270 }
271
test_sync_merge_invalid(void)272 static void test_sync_merge_invalid(void)
273 {
274 int in_fence;
275 int fence_invalid;
276 int fence_merge;
277 int timeline;
278 char tmppath[] = "/tmp/igt-XXXXXX";
279 int skip = 0;
280
281 timeline = sw_sync_timeline_create();
282 in_fence = sw_sync_timeline_create_fence(timeline, 1);
283
284 fence_invalid = -1;
285 fence_merge = sync_fence_merge(in_fence, fence_invalid);
286 igt_assert_f(fence_merge < 0, "Verify invalid fd (-1) handling");
287
288 fence_invalid = drm_open_driver(DRIVER_ANY);
289 fence_merge = sync_fence_merge(in_fence, fence_invalid);
290 igt_assert_f(fence_merge < 0, "Verify invalid fd (device fd) handling");
291
292 fence_invalid = mkstemp(tmppath);
293 if (fence_invalid == -1) {
294 skip = 1;
295 goto out;
296 }
297 unlink(tmppath);
298 fence_invalid = drm_open_driver(DRIVER_ANY);
299 fence_merge = sync_fence_merge(in_fence, fence_invalid);
300 close(fence_invalid);
301 igt_assert_f(fence_merge < 0, "Verify invalid fd (file fd) handling");
302
303 out:
304 close(in_fence);
305 close(fence_merge);
306 close(timeline);
307 igt_require(skip == 0);
308 }
309
test_sync_merge(void)310 static void test_sync_merge(void)
311 {
312 int in_fence[3];
313 int fence_merge;
314 int timeline;
315 int active, signaled;
316
317 timeline = sw_sync_timeline_create();
318 in_fence[0] = sw_sync_timeline_create_fence(timeline, 1);
319 in_fence[1] = sw_sync_timeline_create_fence(timeline, 2);
320 in_fence[2] = sw_sync_timeline_create_fence(timeline, 3);
321
322 fence_merge = sync_fence_merge(in_fence[0], in_fence[1]);
323 fence_merge = sync_fence_merge(in_fence[2], fence_merge);
324
325 /* confirm all fences have one active point (even d) */
326 active = sync_fence_count_status(in_fence[0],
327 SW_SYNC_FENCE_STATUS_ACTIVE);
328 igt_assert_f(active == 1, "in_fence[0] has too many active fences\n");
329 active = sync_fence_count_status(in_fence[1],
330 SW_SYNC_FENCE_STATUS_ACTIVE);
331 igt_assert_f(active == 1, "in_fence[1] has too many active fences\n");
332 active = sync_fence_count_status(in_fence[2],
333 SW_SYNC_FENCE_STATUS_ACTIVE);
334 igt_assert_f(active == 1, "in_fence[2] has too many active fences\n");
335 active = sync_fence_count_status(fence_merge,
336 SW_SYNC_FENCE_STATUS_ACTIVE);
337 igt_assert_f(active == 1, "fence_merge has too many active fences\n");
338
339 /* confirm that fence_merge is not signaled until the max of fence 0,1,2 */
340 sw_sync_timeline_inc(timeline, 1);
341 signaled = sync_fence_count_status(in_fence[0],
342 SW_SYNC_FENCE_STATUS_SIGNALED);
343 active = sync_fence_count_status(fence_merge,
344 SW_SYNC_FENCE_STATUS_ACTIVE);
345 igt_assert_f(signaled == 1, "in_fence[0] did not signal\n");
346 igt_assert_f(active == 1, "fence_merge signaled too early\n");
347
348 sw_sync_timeline_inc(timeline, 1);
349 signaled = sync_fence_count_status(in_fence[1],
350 SW_SYNC_FENCE_STATUS_SIGNALED);
351 active = sync_fence_count_status(fence_merge,
352 SW_SYNC_FENCE_STATUS_ACTIVE);
353 igt_assert_f(signaled == 1, "in_fence[1] did not signal\n");
354 igt_assert_f(active == 1, "fence_merge signaled too early\n");
355
356 sw_sync_timeline_inc(timeline, 1);
357 signaled = sync_fence_count_status(in_fence[2],
358 SW_SYNC_FENCE_STATUS_SIGNALED);
359 igt_assert_f(signaled == 1, "in_fence[2] did not signal\n");
360 signaled = sync_fence_count_status(fence_merge,
361 SW_SYNC_FENCE_STATUS_SIGNALED);
362 active = sync_fence_count_status(fence_merge,
363 SW_SYNC_FENCE_STATUS_ACTIVE);
364 igt_assert_f(active == 0 && signaled == 1,
365 "fence_merge did not signal\n");
366
367 close(in_fence[0]);
368 close(in_fence[1]);
369 close(in_fence[2]);
370 close(fence_merge);
371 close(timeline);
372 }
373
test_sync_merge_same(void)374 static void test_sync_merge_same(void)
375 {
376 int in_fence[2];
377 int timeline;
378 int signaled;
379
380 timeline = sw_sync_timeline_create();
381 in_fence[0] = sw_sync_timeline_create_fence(timeline, 1);
382 in_fence[1] = sync_fence_merge(in_fence[0], in_fence[0]);
383
384 signaled = sync_fence_count_status(in_fence[0],
385 SW_SYNC_FENCE_STATUS_SIGNALED);
386 igt_assert_f(signaled == 0, "Fence signaled too early\n");
387
388 sw_sync_timeline_inc(timeline, 1);
389 signaled = sync_fence_count_status(in_fence[0],
390 SW_SYNC_FENCE_STATUS_SIGNALED);
391 igt_assert_f(signaled == 1, "Fence did not signal\n");
392
393 close(in_fence[0]);
394 close(in_fence[1]);
395 close(timeline);
396 }
397
test_sync_multi_timeline_wait(void)398 static void test_sync_multi_timeline_wait(void)
399 {
400 int timeline[3];
401 int in_fence[3];
402 int fence_merge;
403 int active, signaled;
404
405 timeline[0] = sw_sync_timeline_create();
406 timeline[1] = sw_sync_timeline_create();
407 timeline[2] = sw_sync_timeline_create();
408
409 in_fence[0] = sw_sync_timeline_create_fence(timeline[0], 5);
410 in_fence[1] = sw_sync_timeline_create_fence(timeline[1], 5);
411 in_fence[2] = sw_sync_timeline_create_fence(timeline[2], 5);
412
413 fence_merge = sync_fence_merge(in_fence[0], in_fence[1]);
414 fence_merge = sync_fence_merge(in_fence[2], fence_merge);
415
416 /* Confirm fence isn't signaled */
417 active = sync_fence_count_status(fence_merge,
418 SW_SYNC_FENCE_STATUS_ACTIVE);
419 igt_assert_f(active == 3, "Fence signaled too early\n");
420
421 igt_assert_f(sync_fence_wait(fence_merge, 0) == -ETIME,
422 "Failure waiting on fence until timeout\n");
423
424 sw_sync_timeline_inc(timeline[0], 5);
425 active = sync_fence_count_status(fence_merge,
426 SW_SYNC_FENCE_STATUS_ACTIVE);
427 signaled = sync_fence_count_status(fence_merge,
428 SW_SYNC_FENCE_STATUS_SIGNALED);
429 igt_assert_f(active == 2 && signaled == 1,
430 "Fence did not signal properly\n");
431
432 sw_sync_timeline_inc(timeline[1], 5);
433 active = sync_fence_count_status(fence_merge,
434 SW_SYNC_FENCE_STATUS_ACTIVE);
435 signaled = sync_fence_count_status(fence_merge,
436 SW_SYNC_FENCE_STATUS_SIGNALED);
437 igt_assert_f(active == 1 && signaled == 2,
438 "Fence did not signal properly\n");
439
440 sw_sync_timeline_inc(timeline[2], 5);
441 active = sync_fence_count_status(fence_merge,
442 SW_SYNC_FENCE_STATUS_ACTIVE);
443 signaled = sync_fence_count_status(fence_merge,
444 SW_SYNC_FENCE_STATUS_SIGNALED);
445 igt_assert_f(active == 0 && signaled == 3,
446 "Fence did not signal properly\n");
447
448 /* confirm you can successfully wait */
449 igt_assert_f(sync_fence_wait(fence_merge, 100) == 0,
450 "Failure waiting on signaled fence\n");
451
452 close(in_fence[0]);
453 close(in_fence[1]);
454 close(in_fence[2]);
455 close(fence_merge);
456 close(timeline[0]);
457 close(timeline[1]);
458 close(timeline[2]);
459 }
460
461 #define MULTI_CONSUMER_THREADS 8
462 #define MULTI_CONSUMER_ITERATIONS (1 << 14)
test_sync_multi_consumer_thread(void * arg)463 static void * test_sync_multi_consumer_thread(void *arg)
464 {
465 data_t *data = arg;
466 int thread_id = data->thread_id;
467 int timeline = data->timeline;
468 int i;
469
470 for (i = 0; i < MULTI_CONSUMER_ITERATIONS; i++) {
471 int next_point = i * MULTI_CONSUMER_THREADS + thread_id;
472 int fence = sw_sync_timeline_create_fence(timeline, next_point);
473
474 if (sync_fence_wait(fence, 1000) < 0)
475 return (void *) 1;
476
477 if (READ_ONCE(*data->counter) != next_point)
478 return (void *) 1;
479
480 sem_post(data->sem);
481 close(fence);
482 }
483 return NULL;
484 }
485
test_sync_multi_consumer(void)486 static void test_sync_multi_consumer(void)
487 {
488
489 data_t data_arr[MULTI_CONSUMER_THREADS];
490 pthread_t thread_arr[MULTI_CONSUMER_THREADS];
491 sem_t sem;
492 int timeline;
493 _Atomic(uint32_t) counter = 0;
494 uintptr_t thread_ret = 0;
495 data_t data;
496 int i, ret;
497
498 sem_init(&sem, 0, 0);
499 timeline = sw_sync_timeline_create();
500
501 data.counter = &counter;
502 data.timeline = timeline;
503 data.sem = &sem;
504
505 /* Start sync threads. */
506 for (i = 0; i < MULTI_CONSUMER_THREADS; i++)
507 {
508 data_arr[i] = data;
509 data_arr[i].thread_id = i;
510 ret = pthread_create(&thread_arr[i], NULL,
511 test_sync_multi_consumer_thread,
512 (void *) &(data_arr[i]));
513 igt_assert_eq(ret, 0);
514 }
515
516 /* Produce 'content'. */
517 for (i = 0; i < MULTI_CONSUMER_THREADS * MULTI_CONSUMER_ITERATIONS; i++)
518 {
519 sem_wait(&sem);
520
521 atomic_fetch_add(&counter, 1);
522 sw_sync_timeline_inc(timeline, 1);
523 }
524
525 /* Wait for threads to complete. */
526 for (i = 0; i < MULTI_CONSUMER_THREADS; i++)
527 {
528 uintptr_t local_thread_ret;
529 pthread_join(thread_arr[i], (void **)&local_thread_ret);
530 thread_ret |= local_thread_ret;
531 }
532
533 close(timeline);
534 sem_destroy(&sem);
535
536 igt_assert_eq(counter,
537 MULTI_CONSUMER_THREADS * MULTI_CONSUMER_ITERATIONS);
538
539 igt_assert_f(thread_ret == 0, "A sync thread reported failure.\n");
540 }
541
542 #define MULTI_CONSUMER_PRODUCER_THREADS 8
543 #define MULTI_CONSUMER_PRODUCER_ITERATIONS (1 << 14)
test_sync_multi_consumer_producer_thread(void * arg)544 static void * test_sync_multi_consumer_producer_thread(void *arg)
545 {
546 data_t *data = arg;
547 int thread_id = data->thread_id;
548 int timeline = data->timeline;
549 int i;
550
551 for (i = 0; i < MULTI_CONSUMER_PRODUCER_ITERATIONS; i++) {
552 int next_point = i * MULTI_CONSUMER_PRODUCER_THREADS + thread_id;
553 int fence = sw_sync_timeline_create_fence(timeline, next_point);
554
555 if (sync_fence_wait(fence, 1000) < 0)
556 return (void *) 1;
557
558 if (atomic_fetch_add(data->counter, 1) != next_point)
559 return (void *) 1;
560
561 /* Kick off the next thread. */
562 sw_sync_timeline_inc(timeline, 1);
563
564 close(fence);
565 }
566 return NULL;
567 }
568
test_sync_multi_consumer_producer(void)569 static void test_sync_multi_consumer_producer(void)
570 {
571 data_t data_arr[MULTI_CONSUMER_PRODUCER_THREADS];
572 pthread_t thread_arr[MULTI_CONSUMER_PRODUCER_THREADS];
573 int timeline;
574 _Atomic(uint32_t) counter = 0;
575 uintptr_t thread_ret = 0;
576 data_t data;
577 int i, ret;
578
579 timeline = sw_sync_timeline_create();
580
581 data.counter = &counter;
582 data.timeline = timeline;
583
584 /* Start consumer threads. */
585 for (i = 0; i < MULTI_CONSUMER_PRODUCER_THREADS; i++)
586 {
587 data_arr[i] = data;
588 data_arr[i].thread_id = i;
589 ret = pthread_create(&thread_arr[i], NULL,
590 test_sync_multi_consumer_producer_thread,
591 (void *) &(data_arr[i]));
592 igt_assert_eq(ret, 0);
593 }
594
595 /* Wait for threads to complete. */
596 for (i = 0; i < MULTI_CONSUMER_PRODUCER_THREADS; i++)
597 {
598 uintptr_t local_thread_ret;
599 pthread_join(thread_arr[i], (void **)&local_thread_ret);
600 thread_ret |= local_thread_ret;
601 }
602
603 close(timeline);
604
605 igt_assert_eq(counter,
606 MULTI_CONSUMER_PRODUCER_THREADS *
607 MULTI_CONSUMER_PRODUCER_ITERATIONS);
608
609 igt_assert_f(thread_ret == 0, "A sync thread reported failure.\n");
610 }
611
test_mspc_wait_on_fence(int fence)612 static int test_mspc_wait_on_fence(int fence)
613 {
614 int error, active;
615
616 do {
617 error = sync_fence_count_status(fence,
618 SW_SYNC_FENCE_STATUS_ERROR);
619 igt_assert_f(error == 0, "Error occurred on fence\n");
620 active = sync_fence_count_status(fence,
621 SW_SYNC_FENCE_STATUS_ACTIVE);
622 } while (active);
623
624 return 0;
625 }
626
627 static struct {
628 int iterations;
629 int threads;
630 int counter;
631 int cons_timeline;
632 int *prod_timeline;
633 pthread_mutex_t lock;
634 } test_mpsc_data;
635
mpsc_producer_thread(void * d)636 static void *mpsc_producer_thread(void *d)
637 {
638 int id = (long)d;
639 int fence, i;
640 int *prod_timeline = test_mpsc_data.prod_timeline;
641 int cons_timeline = test_mpsc_data.cons_timeline;
642 int iterations = test_mpsc_data.iterations;
643
644 for (i = 0; i < iterations; i++) {
645 fence = sw_sync_timeline_create_fence(cons_timeline, i);
646
647 /* Wait for the consumer to finish. Use alternate
648 * means of waiting on the fence
649 */
650 if ((iterations + id) % 8 != 0) {
651 igt_assert_f(sync_fence_wait(fence, -1) == 0,
652 "Failure waiting on fence\n");
653 } else {
654 igt_assert_f(test_mspc_wait_on_fence(fence) == 0,
655 "Failure waiting on fence\n");
656 }
657
658 /* Every producer increments the counter, the consumer
659 * checks and erases it
660 */
661 pthread_mutex_lock(&test_mpsc_data.lock);
662 test_mpsc_data.counter++;
663 pthread_mutex_unlock(&test_mpsc_data.lock);
664
665 sw_sync_timeline_inc(prod_timeline[id], 1);
666 close(fence);
667 }
668
669 return NULL;
670 }
671
mpsc_consumer_thread(void)672 static int mpsc_consumer_thread(void)
673 {
674 int fence, merged, tmp, it, i;
675 int *prod_timeline = test_mpsc_data.prod_timeline;
676 int cons_timeline = test_mpsc_data.cons_timeline;
677 int iterations = test_mpsc_data.iterations;
678 int n = test_mpsc_data.threads;
679
680 for (it = 1; it <= iterations; it++) {
681 fence = sw_sync_timeline_create_fence(prod_timeline[0], it);
682 for (i = 1; i < n; i++) {
683 tmp = sw_sync_timeline_create_fence(prod_timeline[i], it);
684 merged = sync_fence_merge(tmp, fence);
685 close(tmp);
686 close(fence);
687 fence = merged;
688 }
689
690 /* Make sure we see an increment from every producer thread.
691 * Vary the means by which we wait.
692 */
693 if (iterations % 8 != 0) {
694 igt_assert_f(sync_fence_wait(fence, -1) == 0,
695 "Producers did not increment as expected\n");
696 } else {
697 igt_assert_f(test_mspc_wait_on_fence(fence) == 0,
698 "Failure waiting on fence\n");
699 }
700
701 igt_assert_f(test_mpsc_data.counter == n * it,
702 "Counter value mismatch\n");
703
704 /* Release the producer threads */
705 sw_sync_timeline_inc(cons_timeline, 1);
706 close(fence);
707 }
708
709 return 0;
710 }
711
712 /* IMPORTANT NOTE: if you see this test failing on your system, it may be
713 * due to a shortage of file descriptors. Please ensure your system has
714 * a sensible limit for this test to finish correctly.
715 */
test_sync_multi_producer_single_consumer(void)716 static void test_sync_multi_producer_single_consumer(void)
717 {
718 int iterations = 1 << 12;
719 int n = 5;
720 int prod_timeline[n];
721 int cons_timeline;
722 pthread_t threads[n];
723 long i;
724
725 cons_timeline = sw_sync_timeline_create();
726 for (i = 0; i < n; i++)
727 prod_timeline[i] = sw_sync_timeline_create();
728
729 test_mpsc_data.prod_timeline = prod_timeline;
730 test_mpsc_data.cons_timeline = cons_timeline;
731 test_mpsc_data.iterations = iterations;
732 test_mpsc_data.threads = n;
733 test_mpsc_data.counter = 0;
734 pthread_mutex_init(&test_mpsc_data.lock, NULL);
735
736 for (i = 0; i < n; i++) {
737 pthread_create(&threads[i], NULL, (void * (*)(void *))
738 mpsc_producer_thread,
739 (void *)i);
740 }
741
742 mpsc_consumer_thread();
743
744 for (i = 0; i < n; i++)
745 pthread_join(threads[i], NULL);
746 }
747
test_sync_expired_merge(void)748 static void test_sync_expired_merge(void)
749 {
750 int iterations = 1 << 20;
751 int timeline;
752 int i;
753 int fence_expired, fence_merged;
754
755 timeline = sw_sync_timeline_create();
756
757 sw_sync_timeline_inc(timeline, 100);
758 fence_expired = sw_sync_timeline_create_fence(timeline, 1);
759 igt_assert_f(sync_fence_wait(fence_expired, 0) == 0,
760 "Failure waiting for expired fence\n");
761
762 fence_merged = sync_fence_merge(fence_expired, fence_expired);
763 close(fence_merged);
764
765 for (i = 0; i < iterations; i++) {
766 int fence = sync_fence_merge(fence_expired, fence_expired);
767
768 igt_assert_f(sync_fence_wait(fence, -1) == 0,
769 "Failure waiting on fence\n");
770 close(fence);
771 }
772
773 close(fence_expired);
774 }
775
test_sync_random_merge(void)776 static void test_sync_random_merge(void)
777 {
778 int i, size;
779 const int nbr_timeline = 32;
780 const int nbr_merge = 1024;
781 int fence_map[nbr_timeline];
782 int timeline_arr[nbr_timeline];
783 int fence, tmpfence, merged;
784 int timeline, timeline_offset, sync_pt;
785
786 srand(time(NULL));
787
788 for (i = 0; i < nbr_timeline; i++) {
789 timeline_arr[i] = sw_sync_timeline_create();
790 fence_map[i] = -1;
791 }
792
793 sync_pt = rand();
794 fence = sw_sync_timeline_create_fence(timeline_arr[0], sync_pt);
795
796 fence_map[0] = sync_pt;
797
798 /* Randomly create syncpoints out of a fixed set of timelines,
799 * and merge them together.
800 */
801 for (i = 0; i < nbr_merge; i++) {
802 /* Generate syncpoint. */
803 timeline_offset = rand() % nbr_timeline;
804 timeline = timeline_arr[timeline_offset];
805 sync_pt = rand();
806
807 /* Keep track of the latest sync_pt in each timeline. */
808 if (fence_map[timeline_offset] == -1)
809 fence_map[timeline_offset] = sync_pt;
810 else if (fence_map[timeline_offset] < sync_pt)
811 fence_map[timeline_offset] = sync_pt;
812
813 /* Merge. */
814 tmpfence = sw_sync_timeline_create_fence(timeline, sync_pt);
815 merged = sync_fence_merge(tmpfence, fence);
816 close(tmpfence);
817 close(fence);
818 fence = merged;
819 }
820
821 size = 0;
822 for (i = 0; i < nbr_timeline; i++)
823 if (fence_map[i] != -1)
824 size++;
825
826 /* Trigger the merged fence. */
827 for (i = 0; i < nbr_timeline; i++) {
828 if (fence_map[i] != -1) {
829 igt_assert_f(sync_fence_wait(fence, 0) == -ETIME,
830 "Failure waiting on fence until timeout\n");
831 /* Increment the timeline to the last sync_pt */
832 sw_sync_timeline_inc(timeline_arr[i], fence_map[i]);
833 }
834 }
835
836 /* Check that the fence is triggered. */
837 igt_assert_f(sync_fence_wait(fence, 1) == 0,
838 "Failure triggering fence\n");
839
840 close(fence);
841 for (i = 0; i < nbr_timeline; i++)
842 close(timeline_arr[i]);
843 }
844
845 igt_main
846 {
847 igt_fixture
848 igt_require_sw_sync();
849
850 igt_subtest("alloc_timeline")
851 test_alloc_timeline();
852
853 igt_subtest("alloc_fence")
854 test_alloc_fence();
855
856 igt_subtest("alloc_fence_invalid_timeline")
857 test_alloc_fence_invalid_timeline();
858
859 igt_subtest("timeline_closed")
860 test_timeline_closed();
861
862 igt_subtest("timeline_closed_signaled")
863 test_timeline_closed_signaled();
864
865 igt_subtest("alloc_merge_fence")
866 test_alloc_merge_fence();
867
868 igt_subtest("sync_busy")
869 test_sync_busy();
870
871 igt_subtest("sync_busy_fork")
872 test_sync_busy_fork();
873
874 igt_subtest("sync_busy_fork_unixsocket")
875 test_sync_busy_fork_unixsocket();
876
877 igt_subtest("sync_merge_invalid")
878 test_sync_merge_invalid();
879
880 igt_subtest("sync_merge")
881 test_sync_merge();
882
883 igt_subtest("sync_merge_same")
884 test_sync_merge_same();
885
886 igt_subtest("sync_multi_timeline_wait")
887 test_sync_multi_timeline_wait();
888
889 igt_subtest("sync_multi_consumer")
890 test_sync_multi_consumer();
891
892 igt_subtest("sync_multi_consumer_producer")
893 test_sync_multi_consumer_producer();
894
895 igt_subtest("sync_multi_producer_single_consumer")
896 test_sync_multi_producer_single_consumer();
897
898 igt_subtest("sync_expired_merge")
899 test_sync_expired_merge();
900
901 igt_subtest("sync_random_merge")
902 test_sync_random_merge();
903 }
904