xref: /aosp_15_r20/external/igt-gpu-tools/tests/sw_sync.c (revision d83cc019efdc2edc6c4b16e9034a3ceb8d35d77c)
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