]> git.ipfire.org Git - thirdparty/strongswan.git/blame - src/libstrongswan/tests/suites/test_threading.c
identification: Support prefixes in string constructors for an explicit type
[thirdparty/strongswan.git] / src / libstrongswan / tests / suites / test_threading.c
CommitLineData
552cc11b 1/*
de42bf35 2 * Copyright (C) 2013 Tobias Brunner
552cc11b
MW
3 * Copyright (C) 2008 Martin Willi
4 * Hochschule fuer Technik Rapperswil
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 */
16
95e99150
TB
17#include "test_suite.h"
18
855747ea 19#include <unistd.h>
f23fd4c5
MW
20
21#include <threading/thread.h>
de42bf35 22#include <threading/mutex.h>
f23fd4c5 23#include <threading/condvar.h>
dac31fe1 24#include <threading/rwlock.h>
f644b9e8 25#include <threading/rwlock_condvar.h>
b1bfe595 26#include <threading/spinlock.h>
ffab2e0c 27#include <threading/semaphore.h>
0b00e63e 28#include <threading/thread_value.h>
552cc11b 29
de42bf35
TB
30/*******************************************************************************
31 * recursive mutex test
32 */
552cc11b 33
de42bf35
TB
34#define THREADS 20
35
f23fd4c5
MW
36/**
37 * Thread barrier data
38 */
39typedef struct {
40 mutex_t *mutex;
41 condvar_t *cond;
42 int count;
43 int current;
44 bool active;
45} barrier_t;
46
47/**
48 * Create a thread barrier for count threads
49 */
50static barrier_t* barrier_create(int count)
51{
52 barrier_t *this;
552cc11b 53
f23fd4c5
MW
54 INIT(this,
55 .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
56 .cond = condvar_create(CONDVAR_TYPE_DEFAULT),
57 .count = count,
58 );
59
60 return this;
61}
62
63/**
64 * Destroy a thread barrier
65 */
66static void barrier_destroy(barrier_t *this)
67{
68 this->mutex->destroy(this->mutex);
69 this->cond->destroy(this->cond);
70 free(this);
71}
552cc11b 72
f23fd4c5
MW
73/**
74 * Wait to have configured number of threads in barrier
75 */
76static bool barrier_wait(barrier_t *this)
77{
78 bool winner = FALSE;
79
80 this->mutex->lock(this->mutex);
81 if (!this->active)
82 { /* first, reset */
83 this->active = TRUE;
84 this->current = 0;
85 }
86
87 this->current++;
88 while (this->current < this->count)
89 {
90 this->cond->wait(this->cond, this->mutex);
91 }
92 if (this->active)
93 { /* first, win */
94 winner = TRUE;
95 this->active = FALSE;
96 }
97 this->mutex->unlock(this->mutex);
98 this->cond->broadcast(this->cond);
99 sched_yield();
100
101 return winner;
102}
103
104/**
105 * Barrier for some tests
106 */
107static barrier_t *barrier;
552cc11b 108
13183a74
MW
109/**
110 * A mutex for tests requiring one
111 */
112static mutex_t *mutex;
113
114/**
115 * A condvar for tests requiring one
116 */
117static condvar_t *condvar;
118
119/**
120 * A counter for signaling
121 */
122static int sigcount;
123
de42bf35 124static void *mutex_run(void *data)
552cc11b 125{
13183a74 126 int locked = 0;
552cc11b
MW
127 int i;
128
129 /* wait for all threads before getting in action */
f23fd4c5 130 barrier_wait(barrier);
552cc11b
MW
131
132 for (i = 0; i < 100; i++)
133 {
134 mutex->lock(mutex);
135 mutex->lock(mutex);
136 mutex->lock(mutex);
f23fd4c5 137 locked++;
552cc11b 138 sched_yield();
f23fd4c5 139 if (locked > 1)
552cc11b 140 {
de42bf35 141 fail("two threads locked the mutex concurrently");
7daf5226 142 }
f23fd4c5 143 locked--;
552cc11b
MW
144 mutex->unlock(mutex);
145 mutex->unlock(mutex);
146 mutex->unlock(mutex);
147 }
148 return NULL;
149}
150
de42bf35 151START_TEST(test_mutex)
552cc11b 152{
f23fd4c5 153 thread_t *threads[THREADS];
de42bf35 154 int i;
7daf5226 155
f23fd4c5 156 barrier = barrier_create(THREADS);
3901937d 157 mutex = mutex_create(MUTEX_TYPE_RECURSIVE);
7daf5226 158
552cc11b
MW
159 for (i = 0; i < 10; i++)
160 {
161 mutex->lock(mutex);
162 mutex->unlock(mutex);
163 }
164 for (i = 0; i < 10; i++)
165 {
166 mutex->lock(mutex);
167 }
168 for (i = 0; i < 10; i++)
169 {
170 mutex->unlock(mutex);
171 }
7daf5226 172
552cc11b
MW
173 for (i = 0; i < THREADS; i++)
174 {
13183a74 175 threads[i] = thread_create(mutex_run, NULL);
552cc11b
MW
176 }
177 for (i = 0; i < THREADS; i++)
178 {
f23fd4c5 179 threads[i]->join(threads[i]);
552cc11b 180 }
7daf5226 181
552cc11b 182 mutex->destroy(mutex);
f23fd4c5 183 barrier_destroy(barrier);
552cc11b 184}
de42bf35 185END_TEST
552cc11b 186
b1bfe595
MW
187/**
188 * Spinlock for testing
189 */
190static spinlock_t *spinlock;
191
192static void *spinlock_run(void *data)
193{
194 int i, *locked = (int*)data;
195
196 barrier_wait(barrier);
197
198 for (i = 0; i < 1000; i++)
199 {
200 spinlock->lock(spinlock);
201 (*locked)++;
202 ck_assert_int_eq(*locked, 1);
203 (*locked)--;
204 spinlock->unlock(spinlock);
205 }
206 return NULL;
207}
208
209START_TEST(test_spinlock)
210{
211 thread_t *threads[THREADS];
212 int i, locked = 0;
213
214 barrier = barrier_create(THREADS);
215 spinlock = spinlock_create();
216
217 for (i = 0; i < THREADS; i++)
218 {
219 threads[i] = thread_create(spinlock_run, &locked);
220 }
221 for (i = 0; i < THREADS; i++)
222 {
223 threads[i]->join(threads[i]);
224 }
225
226 spinlock->destroy(spinlock);
227 barrier_destroy(barrier);
228}
229END_TEST
230
13183a74
MW
231static void *condvar_run(void *data)
232{
233 mutex->lock(mutex);
234 sigcount++;
235 condvar->signal(condvar);
236 mutex->unlock(mutex);
237 return NULL;
238}
239
240START_TEST(test_condvar)
241{
242 thread_t *threads[THREADS];
243 int i;
244
245 mutex = mutex_create(MUTEX_TYPE_DEFAULT);
246 condvar = condvar_create(CONDVAR_TYPE_DEFAULT);
247 sigcount = 0;
248
249 for (i = 0; i < THREADS; i++)
250 {
251 threads[i] = thread_create(condvar_run, NULL);
252 }
253
254 mutex->lock(mutex);
255 while (sigcount < THREADS)
256 {
257 condvar->wait(condvar, mutex);
258 }
259 mutex->unlock(mutex);
260
261 for (i = 0; i < THREADS; i++)
262 {
263 threads[i]->join(threads[i]);
264 }
265
266 mutex->destroy(mutex);
267 condvar->destroy(condvar);
268}
269END_TEST
270
b7db393d
MW
271static void *condvar_recursive_run(void *data)
272{
273 mutex->lock(mutex);
274 mutex->lock(mutex);
275 mutex->lock(mutex);
276 sigcount++;
277 condvar->signal(condvar);
278 mutex->unlock(mutex);
279 mutex->unlock(mutex);
280 mutex->unlock(mutex);
281 return NULL;
282}
283
284START_TEST(test_condvar_recursive)
285{
286 thread_t *threads[THREADS];
287 int i;
288
289 mutex = mutex_create(MUTEX_TYPE_RECURSIVE);
290 condvar = condvar_create(CONDVAR_TYPE_DEFAULT);
291 sigcount = 0;
292
293 mutex->lock(mutex);
294
295 for (i = 0; i < THREADS; i++)
296 {
297 threads[i] = thread_create(condvar_recursive_run, NULL);
298 }
299
300 mutex->lock(mutex);
301 mutex->lock(mutex);
302 while (sigcount < THREADS)
303 {
304 condvar->wait(condvar, mutex);
305 }
306 mutex->unlock(mutex);
307 mutex->unlock(mutex);
308 mutex->unlock(mutex);
309
310 for (i = 0; i < THREADS; i++)
311 {
312 threads[i]->join(threads[i]);
313 }
314
315 mutex->destroy(mutex);
316 condvar->destroy(condvar);
317}
318END_TEST
319
9a0a891e
MW
320static void *condvar_run_broad(void *data)
321{
322 mutex->lock(mutex);
323 while (sigcount < 0)
324 {
325 condvar->wait(condvar, mutex);
326 }
327 mutex->unlock(mutex);
328 return NULL;
329}
330
331START_TEST(test_condvar_broad)
332{
333 thread_t *threads[THREADS];
334 int i;
335
336 mutex = mutex_create(MUTEX_TYPE_DEFAULT);
337 condvar = condvar_create(CONDVAR_TYPE_DEFAULT);
338 sigcount = 0;
339
340 for (i = 0; i < THREADS; i++)
341 {
342 threads[i] = thread_create(condvar_run_broad, NULL);
343 }
344
345 sched_yield();
346
347 mutex->lock(mutex);
348 sigcount = 1;
349 condvar->broadcast(condvar);
350 mutex->unlock(mutex);
351
352 for (i = 0; i < THREADS; i++)
353 {
354 threads[i]->join(threads[i]);
355 }
356
357 mutex->destroy(mutex);
358 condvar->destroy(condvar);
359}
360END_TEST
361
31f9f777
MW
362START_TEST(test_condvar_timed)
363{
364 thread_t *thread;
365 timeval_t start, end, diff = { .tv_usec = 50000 };
366
367 mutex = mutex_create(MUTEX_TYPE_DEFAULT);
368 condvar = condvar_create(CONDVAR_TYPE_DEFAULT);
369 sigcount = 0;
370
371 mutex->lock(mutex);
372 while (TRUE)
373 {
374 time_monotonic(&start);
375 if (condvar->timed_wait(condvar, mutex, diff.tv_usec / 1000))
376 {
377 break;
378 }
379 }
380 time_monotonic(&end);
381 mutex->unlock(mutex);
382 timersub(&end, &start, &end);
383 ck_assert_msg(timercmp(&end, &diff, >), "end: %u.%u, diff: %u.%u",
384 end.tv_sec, end.tv_usec, diff.tv_sec, diff.tv_usec);
385
386 thread = thread_create(condvar_run, NULL);
387
388 mutex->lock(mutex);
389 while (sigcount == 0)
390 {
391 ck_assert(!condvar->timed_wait(condvar, mutex, 1000));
392 }
393 mutex->unlock(mutex);
394
395 thread->join(thread);
396 mutex->destroy(mutex);
397 condvar->destroy(condvar);
398}
399END_TEST
400
8699a32b
MW
401START_TEST(test_condvar_timed_abs)
402{
403 thread_t *thread;
404 timeval_t start, end, abso, diff = { .tv_usec = 50000 };
405
406 mutex = mutex_create(MUTEX_TYPE_DEFAULT);
407 condvar = condvar_create(CONDVAR_TYPE_DEFAULT);
408 sigcount = 0;
409
410 mutex->lock(mutex);
411 while (TRUE)
412 {
413 time_monotonic(&start);
414 timeradd(&start, &diff, &abso);
415 if (condvar->timed_wait_abs(condvar, mutex, abso))
416 {
417 break;
418 }
419 }
420 time_monotonic(&end);
421 mutex->unlock(mutex);
422 ck_assert_msg(timercmp(&end, &diff, >), "end: %u.%u, diff: %u.%u",
423 end.tv_sec, end.tv_usec, abso.tv_sec, abso.tv_usec);
424
425 thread = thread_create(condvar_run, NULL);
426
427 time_monotonic(&start);
428 diff.tv_sec = 1;
429 timeradd(&start, &diff, &abso);
430 mutex->lock(mutex);
431 while (sigcount == 0)
432 {
433 ck_assert(!condvar->timed_wait_abs(condvar, mutex, abso));
434 }
435 mutex->unlock(mutex);
436
437 thread->join(thread);
438 mutex->destroy(mutex);
439 condvar->destroy(condvar);
440}
441END_TEST
442
8b25b5c3
MW
443static void *condvar_cancel_run(void *data)
444{
445 thread_cancelability(FALSE);
446
447 mutex->lock(mutex);
448
449 sigcount++;
450 condvar->broadcast(condvar);
451
452 thread_cleanup_push((void*)mutex->unlock, mutex);
453 thread_cancelability(TRUE);
454 while (TRUE)
455 {
456 condvar->wait(condvar, mutex);
457 }
458 thread_cleanup_pop(TRUE);
459
460 return NULL;
461}
462
463START_TEST(test_condvar_cancel)
464{
465 thread_t *threads[THREADS];
466 int i;
467
468 mutex = mutex_create(MUTEX_TYPE_DEFAULT);
469 condvar = condvar_create(CONDVAR_TYPE_DEFAULT);
470 sigcount = 0;
471
472 for (i = 0; i < THREADS; i++)
473 {
474 threads[i] = thread_create(condvar_cancel_run, NULL);
475 }
476
477 /* wait for all threads */
478 mutex->lock(mutex);
479 while (sigcount < THREADS)
480 {
481 condvar->wait(condvar, mutex);
482 }
483 mutex->unlock(mutex);
484
485 for (i = 0; i < THREADS; i++)
486 {
487 threads[i]->cancel(threads[i]);
488 }
489 for (i = 0; i < THREADS; i++)
490 {
491 threads[i]->join(threads[i]);
492 }
493
494 mutex->destroy(mutex);
495 condvar->destroy(condvar);
496}
497END_TEST
498
dac31fe1
MW
499/**
500 * RWlock for different tests
501 */
502static rwlock_t *rwlock;
503
504static void *rwlock_run(refcount_t *refs)
505{
506 rwlock->read_lock(rwlock);
507 ref_get(refs);
508 sched_yield();
509 ignore_result(ref_put(refs));
510 rwlock->unlock(rwlock);
511
512 if (rwlock->try_write_lock(rwlock))
513 {
514 ck_assert_int_eq(*refs, 0);
515 sched_yield();
516 rwlock->unlock(rwlock);
517 }
518
519 rwlock->write_lock(rwlock);
520 ck_assert_int_eq(*refs, 0);
521 sched_yield();
522 rwlock->unlock(rwlock);
523
524 rwlock->read_lock(rwlock);
525 rwlock->read_lock(rwlock);
526 ref_get(refs);
527 sched_yield();
528 ignore_result(ref_put(refs));
529 rwlock->unlock(rwlock);
530 rwlock->unlock(rwlock);
531
532 return NULL;
533}
534
535START_TEST(test_rwlock)
536{
537 thread_t *threads[THREADS];
538 refcount_t refs = 0;
539 int i;
540
541 rwlock = rwlock_create(RWLOCK_TYPE_DEFAULT);
542
543 for (i = 0; i < THREADS; i++)
544 {
545 threads[i] = thread_create((void*)rwlock_run, &refs);
546 }
547 for (i = 0; i < THREADS; i++)
548 {
549 threads[i]->join(threads[i]);
550 }
551
552 rwlock->destroy(rwlock);
553}
554END_TEST
555
6a3f0467
MW
556static void *rwlock_try_run(void *param)
557{
558 if (rwlock->try_write_lock(rwlock))
559 {
560 rwlock->unlock(rwlock);
561 return param;
562 }
563 return NULL;
564}
565
566START_TEST(test_rwlock_try)
567{
568 uintptr_t magic = 0xcafebabe;
569 thread_t *thread;
570
571 rwlock = rwlock_create(RWLOCK_TYPE_DEFAULT);
572
573 thread = thread_create(rwlock_try_run, (void*)magic);
574 ck_assert_int_eq((uintptr_t)thread->join(thread), magic);
575
576 rwlock->read_lock(rwlock);
577 thread = thread_create(rwlock_try_run, (void*)magic);
578 ck_assert(thread->join(thread) == NULL);
579 rwlock->unlock(rwlock);
580
581 rwlock->read_lock(rwlock);
582 rwlock->read_lock(rwlock);
583 rwlock->read_lock(rwlock);
584 thread = thread_create(rwlock_try_run, (void*)magic);
585 ck_assert(thread->join(thread) == NULL);
586 rwlock->unlock(rwlock);
587 rwlock->unlock(rwlock);
588 rwlock->unlock(rwlock);
589
590 rwlock->write_lock(rwlock);
591 thread = thread_create(rwlock_try_run, (void*)magic);
592 ck_assert(thread->join(thread) == NULL);
593 rwlock->unlock(rwlock);
594
595 rwlock->destroy(rwlock);
596}
597END_TEST
598
f644b9e8
MW
599/**
600 * Rwlock condvar
601 */
602static rwlock_condvar_t *rwcond;
603
604static void *rwlock_condvar_run(void *data)
605{
606 rwlock->write_lock(rwlock);
607 sigcount++;
608 rwcond->signal(rwcond);
609 rwlock->unlock(rwlock);
610 return NULL;
611}
612
613START_TEST(test_rwlock_condvar)
614{
615 thread_t *threads[THREADS];
616 int i;
617
618 rwlock = rwlock_create(RWLOCK_TYPE_DEFAULT);
619 rwcond = rwlock_condvar_create();
620 sigcount = 0;
621
622 for (i = 0; i < THREADS; i++)
623 {
624 threads[i] = thread_create(rwlock_condvar_run, NULL);
625 }
626
627 rwlock->write_lock(rwlock);
628 while (sigcount < THREADS)
629 {
630 rwcond->wait(rwcond, rwlock);
631 }
632 rwlock->unlock(rwlock);
633
634 for (i = 0; i < THREADS; i++)
635 {
636 threads[i]->join(threads[i]);
637 }
638
639 rwlock->destroy(rwlock);
640 rwcond->destroy(rwcond);
641}
642END_TEST
643
1032f52d
MW
644static void *rwlock_condvar_run_broad(void *data)
645{
646 rwlock->write_lock(rwlock);
647 while (sigcount < 0)
648 {
649 rwcond->wait(rwcond, rwlock);
650 }
651 rwlock->unlock(rwlock);
652 return NULL;
653}
654
655START_TEST(test_rwlock_condvar_broad)
656{
657 thread_t *threads[THREADS];
658 int i;
659
660 rwlock = rwlock_create(RWLOCK_TYPE_DEFAULT);
661 rwcond = rwlock_condvar_create();
662 sigcount = 0;
663
664 for (i = 0; i < THREADS; i++)
665 {
666 threads[i] = thread_create(rwlock_condvar_run_broad, NULL);
667 }
668
669 sched_yield();
670
671 rwlock->write_lock(rwlock);
672 sigcount = 1;
673 rwcond->broadcast(rwcond);
674 rwlock->unlock(rwlock);
675
676 for (i = 0; i < THREADS; i++)
677 {
678 threads[i]->join(threads[i]);
679 }
680
681 rwlock->destroy(rwlock);
682 rwcond->destroy(rwcond);
683}
684END_TEST
685
af19213c
MW
686START_TEST(test_rwlock_condvar_timed)
687{
688 thread_t *thread;
689 timeval_t start, end, diff = { .tv_usec = 50000 };
690
691 rwlock = rwlock_create(RWLOCK_TYPE_DEFAULT);
692 rwcond = rwlock_condvar_create();
693 sigcount = 0;
694
695 rwlock->write_lock(rwlock);
696 while (TRUE)
697 {
698 time_monotonic(&start);
699 if (rwcond->timed_wait(rwcond, rwlock, diff.tv_usec / 1000))
700 {
701 break;
702 }
703 }
704 rwlock->unlock(rwlock);
705 time_monotonic(&end);
706 timersub(&end, &start, &end);
707 ck_assert_msg(timercmp(&end, &diff, >), "end: %u.%u, diff: %u.%u",
708 end.tv_sec, end.tv_usec, diff.tv_sec, diff.tv_usec);
709
710 thread = thread_create(rwlock_condvar_run, NULL);
711
712 rwlock->write_lock(rwlock);
713 while (sigcount == 0)
714 {
715 ck_assert(!rwcond->timed_wait(rwcond, rwlock, 1000));
716 }
717 rwlock->unlock(rwlock);
718
719 thread->join(thread);
720 rwlock->destroy(rwlock);
721 rwcond->destroy(rwcond);
722}
723END_TEST
724
b92c173b
MW
725START_TEST(test_rwlock_condvar_timed_abs)
726{
727 thread_t *thread;
728 timeval_t start, end, abso, diff = { .tv_usec = 50000 };
729
730 rwlock = rwlock_create(RWLOCK_TYPE_DEFAULT);
731 rwcond = rwlock_condvar_create();
732 sigcount = 0;
733
734 rwlock->write_lock(rwlock);
735 while (TRUE)
736 {
737 time_monotonic(&start);
738 timeradd(&start, &diff, &abso);
739 if (rwcond->timed_wait_abs(rwcond, rwlock, abso))
740 {
741 break;
742 }
743 }
744 rwlock->unlock(rwlock);
745 time_monotonic(&end);
746 ck_assert_msg(timercmp(&end, &abso, >), "end: %u.%u, abso: %u.%u",
747 end.tv_sec, end.tv_usec, abso.tv_sec, abso.tv_usec);
748
749 thread = thread_create(rwlock_condvar_run, NULL);
750
751 time_monotonic(&start);
752 diff.tv_sec = 1;
753 timeradd(&start, &diff, &abso);
754 rwlock->write_lock(rwlock);
755 while (sigcount == 0)
756 {
757 ck_assert(!rwcond->timed_wait_abs(rwcond, rwlock, abso));
758 }
759 rwlock->unlock(rwlock);
760
761 thread->join(thread);
762 rwlock->destroy(rwlock);
763 rwcond->destroy(rwcond);
764}
765END_TEST
766
478dc025
MW
767static void *rwlock_condvar_cancel_run(void *data)
768{
769 thread_cancelability(FALSE);
770
771 rwlock->write_lock(rwlock);
772
773 sigcount++;
774 rwcond->broadcast(rwcond);
775
776 thread_cleanup_push((void*)rwlock->unlock, rwlock);
777 thread_cancelability(TRUE);
778 while (TRUE)
779 {
780 rwcond->wait(rwcond, rwlock);
781 }
782 thread_cleanup_pop(TRUE);
783
784 return NULL;
785}
786
787START_TEST(test_rwlock_condvar_cancel)
788{
789 thread_t *threads[THREADS];
790 int i;
791
792 rwlock = rwlock_create(RWLOCK_TYPE_DEFAULT);
793 rwcond = rwlock_condvar_create();
794 sigcount = 0;
795
796 for (i = 0; i < THREADS; i++)
797 {
798 threads[i] = thread_create(rwlock_condvar_cancel_run, NULL);
799 }
800
801 /* wait for all threads */
802 rwlock->write_lock(rwlock);
803 while (sigcount < THREADS)
804 {
805 rwcond->wait(rwcond, rwlock);
806 }
807 rwlock->unlock(rwlock);
808
809 for (i = 0; i < THREADS; i++)
810 {
811 threads[i]->cancel(threads[i]);
812 }
813 for (i = 0; i < THREADS; i++)
814 {
815 threads[i]->join(threads[i]);
816 }
817
818 rwlock->destroy(rwlock);
819 rwcond->destroy(rwcond);
820}
821END_TEST
822
ffab2e0c
MW
823/**
824 * Semaphore for different tests
825 */
826static semaphore_t *semaphore;
827
828static void *semaphore_run(void *data)
829{
830 semaphore->post(semaphore);
831 return NULL;
832}
833
834START_TEST(test_semaphore)
835{
836 thread_t *threads[THREADS];
837 int i, initial = 5;
838
839 semaphore = semaphore_create(initial);
840
841 for (i = 0; i < THREADS; i++)
842 {
843 threads[i] = thread_create(semaphore_run, NULL);
844 }
845 for (i = 0; i < THREADS + initial; i++)
846 {
847 semaphore->wait(semaphore);
848 }
849 for (i = 0; i < THREADS; i++)
850 {
851 threads[i]->join(threads[i]);
852 }
853
854 semaphore->destroy(semaphore);
855}
856END_TEST
857
a14935ea
MW
858START_TEST(test_semaphore_timed)
859{
860 thread_t *thread;
861 timeval_t start, end, diff = { .tv_usec = 50000 };
862
863 semaphore = semaphore_create(0);
864
865 time_monotonic(&start);
866 ck_assert(semaphore->timed_wait(semaphore, diff.tv_usec / 1000));
867 time_monotonic(&end);
868 timersub(&end, &start, &end);
869 ck_assert_msg(timercmp(&end, &diff, >), "end: %u.%u, diff: %u.%u",
870 end.tv_sec, end.tv_usec, diff.tv_sec, diff.tv_usec);
871
872 thread = thread_create(semaphore_run, NULL);
873
874 ck_assert(!semaphore->timed_wait(semaphore, 1000));
875
876 thread->join(thread);
877 semaphore->destroy(semaphore);
878}
879END_TEST
880
fae1b852
MW
881START_TEST(test_semaphore_timed_abs)
882{
883 thread_t *thread;
884 timeval_t start, end, abso, diff = { .tv_usec = 50000 };
885
886 semaphore = semaphore_create(0);
887
888 time_monotonic(&start);
889 timeradd(&start, &diff, &abso);
890 ck_assert(semaphore->timed_wait_abs(semaphore, abso));
891 time_monotonic(&end);
892 ck_assert_msg(timercmp(&end, &abso, >), "end: %u.%u, abso: %u.%u",
893 end.tv_sec, end.tv_usec, abso.tv_sec, abso.tv_usec);
894
895 thread = thread_create(semaphore_run, NULL);
896
897 time_monotonic(&start);
898 diff.tv_sec = 1;
899 timeradd(&start, &diff, &abso);
900 ck_assert(!semaphore->timed_wait_abs(semaphore, abso));
901
902 thread->join(thread);
903 semaphore->destroy(semaphore);
904}
905END_TEST
906
a4cbda35
MW
907static void *semaphore_cancel_run(void *data)
908{
909 refcount_t *ready = (refcount_t*)data;
910
911 thread_cancelability(FALSE);
912 ref_get(ready);
913
914 thread_cancelability(TRUE);
915 semaphore->wait(semaphore);
916
917 ck_assert(FALSE);
918 return NULL;
919}
920
921START_TEST(test_semaphore_cancel)
922{
923 thread_t *threads[THREADS];
924 refcount_t ready = 0;
925 int i;
926
927 semaphore = semaphore_create(0);
928
929 for (i = 0; i < THREADS; i++)
930 {
931 threads[i] = thread_create(semaphore_cancel_run, &ready);
932 }
933 while (ready < THREADS)
934 {
935 sched_yield();
936 }
937 for (i = 0; i < THREADS; i++)
938 {
939 threads[i]->cancel(threads[i]);
940 }
941 for (i = 0; i < THREADS; i++)
942 {
943 threads[i]->join(threads[i]);
944 }
945
946 semaphore->destroy(semaphore);
947}
948END_TEST
949
5d4a882f
MW
950static void *join_run(void *data)
951{
952 /* force some context switches */
953 sched_yield();
954 return (void*)((uintptr_t)data + THREADS);
955}
956
957START_TEST(test_join)
958{
959 thread_t *threads[THREADS];
960 int i;
961
962 for (i = 0; i < THREADS; i++)
963 {
964 threads[i] = thread_create(join_run, (void*)(uintptr_t)i);
965 }
966 for (i = 0; i < THREADS; i++)
967 {
968 ck_assert_int_eq((uintptr_t)threads[i]->join(threads[i]), i + THREADS);
969 }
970}
971END_TEST
972
c320c611
MW
973static void *exit_join_run(void *data)
974{
975 sched_yield();
976 thread_exit((void*)((uintptr_t)data + THREADS));
977 /* not reached */
978 ck_assert(FALSE);
979 return NULL;
980}
981
982START_TEST(test_join_exit)
983{
984 thread_t *threads[THREADS];
985 int i;
986
987 for (i = 0; i < THREADS; i++)
988 {
989 threads[i] = thread_create(exit_join_run, (void*)(uintptr_t)i);
990 }
991 for (i = 0; i < THREADS; i++)
992 {
993 ck_assert_int_eq((uintptr_t)threads[i]->join(threads[i]), i + THREADS);
994 }
995}
996END_TEST
997
274e6beb
MW
998static void *detach_run(void *data)
999{
1000 refcount_t *running = (refcount_t*)data;
1001
1002 ignore_result(ref_put(running));
1003 return NULL;
1004}
1005
1006START_TEST(test_detach)
1007{
1008 thread_t *threads[THREADS];
1009 int i;
1010 refcount_t running = 0;
1011
1012 for (i = 0; i < THREADS; i++)
1013 {
1014 ref_get(&running);
1015 threads[i] = thread_create(detach_run, &running);
1016 }
1017 for (i = 0; i < THREADS; i++)
1018 {
1019 threads[i]->detach(threads[i]);
1020 }
1021 while (running > 0)
1022 {
1023 sched_yield();
1024 }
1025 /* no checks done here, but we check that thread state gets cleaned
c6f886ce
TB
1026 * up with leak detective. give the threads time to clean up. */
1027 usleep(10000);
274e6beb
MW
1028}
1029END_TEST
1030
c320c611
MW
1031static void *detach_exit_run(void *data)
1032{
1033 refcount_t *running = (refcount_t*)data;
1034
1035 ignore_result(ref_put(running));
1036 thread_exit(NULL);
1037 /* not reached */
1038 ck_assert(FALSE);
1039 return NULL;
1040}
1041
1042START_TEST(test_detach_exit)
1043{
1044 thread_t *threads[THREADS];
1045 int i;
1046 refcount_t running = 0;
1047
1048 for (i = 0; i < THREADS; i++)
1049 {
1050 ref_get(&running);
1051 threads[i] = thread_create(detach_exit_run, &running);
1052 }
1053 for (i = 0; i < THREADS; i++)
1054 {
1055 threads[i]->detach(threads[i]);
1056 }
1057 while (running > 0)
1058 {
1059 sched_yield();
1060 }
1061 /* no checks done here, but we check that thread state gets cleaned
c6f886ce
TB
1062 * up with leak detective. give the threads time to clean up. */
1063 usleep(10000);
c320c611
MW
1064}
1065END_TEST
1066
855747ea
MW
1067static void *cancel_run(void *data)
1068{
1069 /* default cancellability should be TRUE, so don't change it */
1070 while (TRUE)
1071 {
1072 sleep(10);
1073 }
1074 return NULL;
1075}
1076
1077START_TEST(test_cancel)
1078{
1079 thread_t *threads[THREADS];
1080 int i;
1081
1082 for (i = 0; i < THREADS; i++)
1083 {
1084 threads[i] = thread_create(cancel_run, NULL);
1085 }
1086 for (i = 0; i < THREADS; i++)
1087 {
1088 threads[i]->cancel(threads[i]);
1089 }
1090 for (i = 0; i < THREADS; i++)
1091 {
1092 threads[i]->join(threads[i]);
1093 }
1094}
1095END_TEST
1096
49e6848b
MW
1097static void *cancel_onoff_run(void *data)
1098{
1099 bool *cancellable = (bool*)data;
1100
1101 thread_cancelability(FALSE);
1102 *cancellable = FALSE;
1103
1104 /* we should not get cancelled here */
1105 usleep(50000);
1106
1107 *cancellable = TRUE;
1108 thread_cancelability(TRUE);
1109
1110 /* but here */
1111 while (TRUE)
1112 {
1113 sleep(10);
1114 }
1115 return NULL;
1116}
1117
1118START_TEST(test_cancel_onoff)
1119{
1120 thread_t *threads[THREADS];
1121 bool cancellable[THREADS];
1122 int i;
1123
1124 for (i = 0; i < THREADS; i++)
1125 {
1126 cancellable[i] = TRUE;
1127 threads[i] = thread_create(cancel_onoff_run, &cancellable[i]);
1128 }
1129 for (i = 0; i < THREADS; i++)
1130 {
1131 /* wait until thread has cleared its cancellability */
1132 while (cancellable[i])
1133 {
1134 sched_yield();
1135 }
1136 threads[i]->cancel(threads[i]);
1137 }
1138 for (i = 0; i < THREADS; i++)
1139 {
1140 threads[i]->join(threads[i]);
1141 ck_assert(cancellable[i]);
1142 }
1143}
1144END_TEST
1145
e5b34086
MW
1146static void *cancel_point_run(void *data)
1147{
1148 thread_cancelability(FALSE);
1149 while (TRUE)
1150 {
1151 /* implicitly enables cancellability */
1152 thread_cancellation_point();
1153 }
1154 return NULL;
1155}
1156
1157START_TEST(test_cancel_point)
1158{
1159 thread_t *threads[THREADS];
1160 int i;
1161
1162 for (i = 0; i < THREADS; i++)
1163 {
1164 threads[i] = thread_create(cancel_point_run, NULL);
1165 }
1166 sched_yield();
1167 for (i = 0; i < THREADS; i++)
1168 {
1169 threads[i]->cancel(threads[i]);
1170 }
1171 for (i = 0; i < THREADS; i++)
1172 {
1173 threads[i]->join(threads[i]);
1174 }
1175}
1176END_TEST
1177
4aec0c55
MW
1178static void cleanup1(void *data)
1179{
1180 uintptr_t *value = (uintptr_t*)data;
1181
1182 ck_assert_int_eq(*value, 1);
1183 (*value)++;
1184}
1185
1186static void cleanup2(void *data)
1187{
1188 uintptr_t *value = (uintptr_t*)data;
1189
1190 ck_assert_int_eq(*value, 2);
1191 (*value)++;
1192}
1193
1194static void cleanup3(void *data)
1195{
1196 uintptr_t *value = (uintptr_t*)data;
1197
1198 ck_assert_int_eq(*value, 3);
1199 (*value)++;
1200}
1201
1202static void *cleanup_run(void *data)
1203{
1204 thread_cleanup_push(cleanup3, data);
1205 thread_cleanup_push(cleanup2, data);
1206 thread_cleanup_push(cleanup1, data);
1207 return NULL;
1208}
1209
1210START_TEST(test_cleanup)
1211{
1212 thread_t *threads[THREADS];
1213 uintptr_t values[THREADS];
1214 int i;
1215
1216 for (i = 0; i < THREADS; i++)
1217 {
1218 values[i] = 1;
1219 threads[i] = thread_create(cleanup_run, &values[i]);
1220 }
1221 for (i = 0; i < THREADS; i++)
1222 {
1223 threads[i]->join(threads[i]);
1224 ck_assert_int_eq(values[i], 4);
1225 }
1226}
1227END_TEST
1228
1229static void *cleanup_exit_run(void *data)
1230{
1231 thread_cleanup_push(cleanup3, data);
1232 thread_cleanup_push(cleanup2, data);
1233 thread_cleanup_push(cleanup1, data);
1234 thread_exit(NULL);
1235 ck_assert(FALSE);
1236 return NULL;
1237}
1238
1239START_TEST(test_cleanup_exit)
1240{
1241 thread_t *threads[THREADS];
1242 uintptr_t values[THREADS];
1243 int i;
1244
1245 for (i = 0; i < THREADS; i++)
1246 {
1247 values[i] = 1;
1248 threads[i] = thread_create(cleanup_exit_run, &values[i]);
1249 }
1250 for (i = 0; i < THREADS; i++)
1251 {
1252 threads[i]->join(threads[i]);
1253 ck_assert_int_eq(values[i], 4);
1254 }
1255}
1256END_TEST
1257
1258static void *cleanup_cancel_run(void *data)
1259{
1260 thread_cancelability(FALSE);
1261
b9dfeb5d
TB
1262 barrier_wait(barrier);
1263
4aec0c55
MW
1264 thread_cleanup_push(cleanup3, data);
1265 thread_cleanup_push(cleanup2, data);
1266 thread_cleanup_push(cleanup1, data);
1267
1268 thread_cancelability(TRUE);
1269
1270 while (TRUE)
1271 {
1272 sleep(1);
1273 }
1274 return NULL;
1275}
1276
1277START_TEST(test_cleanup_cancel)
1278{
1279 thread_t *threads[THREADS];
1280 uintptr_t values[THREADS];
1281 int i;
1282
b9dfeb5d 1283 barrier = barrier_create(THREADS+1);
4aec0c55
MW
1284 for (i = 0; i < THREADS; i++)
1285 {
1286 values[i] = 1;
1287 threads[i] = thread_create(cleanup_cancel_run, &values[i]);
1288 }
b9dfeb5d 1289 barrier_wait(barrier);
4aec0c55
MW
1290 for (i = 0; i < THREADS; i++)
1291 {
1292 threads[i]->cancel(threads[i]);
1293 }
1294 for (i = 0; i < THREADS; i++)
1295 {
1296 threads[i]->join(threads[i]);
1297 ck_assert_int_eq(values[i], 4);
1298 }
b9dfeb5d 1299 barrier_destroy(barrier);
4aec0c55
MW
1300}
1301END_TEST
1302
fd26b7ff
MW
1303static void *cleanup_pop_run(void *data)
1304{
1305 thread_cleanup_push(cleanup3, data);
1306 thread_cleanup_push(cleanup2, data);
1307 thread_cleanup_push(cleanup1, data);
1308
1309 thread_cleanup_push(cleanup2, data);
1310 thread_cleanup_pop(FALSE);
1311
1312 thread_cleanup_pop(TRUE);
1313 return NULL;
1314}
1315
1316START_TEST(test_cleanup_pop)
1317{
1318 thread_t *threads[THREADS];
1319 uintptr_t values[THREADS];
1320 int i;
1321
1322 for (i = 0; i < THREADS; i++)
1323 {
1324 values[i] = 1;
1325 threads[i] = thread_create(cleanup_pop_run, &values[i]);
1326 }
1327 for (i = 0; i < THREADS; i++)
1328 {
1329 threads[i]->join(threads[i]);
1330 ck_assert_int_eq(values[i], 4);
1331 }
1332}
1333END_TEST
1334
0b00e63e
MW
1335static thread_value_t *tls[10];
1336
1337static void *tls_run(void *data)
1338{
1339 uintptr_t value = (uintptr_t)data;
1340 int i, j;
1341
1342 for (i = 0; i < countof(tls); i++)
1343 {
1344 ck_assert(tls[i]->get(tls[i]) == NULL);
1345 }
1346 for (i = 0; i < countof(tls); i++)
1347 {
1348 tls[i]->set(tls[i], (void*)(value * i));
1349 }
1350 for (j = 0; j < 1000; j++)
1351 {
1352 for (i = 0; i < countof(tls); i++)
1353 {
1354 tls[i]->set(tls[i], (void*)(value * i));
1355 ck_assert(tls[i]->get(tls[i]) == (void*)(value * i));
1356 }
1357 sched_yield();
1358 }
1359 for (i = 0; i < countof(tls); i++)
1360 {
1361 ck_assert(tls[i]->get(tls[i]) == (void*)(value * i));
1362 }
1363 return (void*)(value + 1);
1364}
1365
1366START_TEST(test_tls)
1367{
1368 thread_t *threads[THREADS];
1369 int i;
1370
1371 for (i = 0; i < countof(tls); i++)
1372 {
1373 tls[i] = thread_value_create(NULL);
1374 }
1375 for (i = 0; i < THREADS; i++)
1376 {
1377 threads[i] = thread_create(tls_run, (void*)(uintptr_t)i);
1378 }
1379
1380 ck_assert_int_eq((uintptr_t)tls_run((void*)(uintptr_t)(THREADS + 1)),
1381 THREADS + 2);
1382
1383 for (i = 0; i < THREADS; i++)
1384 {
1385 ck_assert_int_eq((uintptr_t)threads[i]->join(threads[i]), i + 1);
1386 }
1387 for (i = 0; i < countof(tls); i++)
1388 {
1389 tls[i]->destroy(tls[i]);
1390 }
1391}
1392END_TEST
1393
21df9851
MW
1394static void tls_cleanup(void *data)
1395{
1396 uintptr_t *value = (uintptr_t*)data;
1397
1398 (*value)--;
1399}
1400
1401static void *tls_cleanup_run(void *data)
1402{
1403 int i;
1404
1405 for (i = 0; i < countof(tls); i++)
1406 {
1407 tls[i]->set(tls[i], data);
1408 }
1409 return NULL;
1410}
1411
1412START_TEST(test_tls_cleanup)
1413{
1414 thread_t *threads[THREADS];
1415 uintptr_t values[THREADS], main_value = countof(tls);
1416 int i;
1417
1418 for (i = 0; i < countof(tls); i++)
1419 {
1420 tls[i] = thread_value_create(tls_cleanup);
1421 }
1422 for (i = 0; i < THREADS; i++)
1423 {
1424 values[i] = countof(tls);
1425 threads[i] = thread_create(tls_cleanup_run, &values[i]);
1426 }
1427
1428 tls_cleanup_run(&main_value);
1429
1430 for (i = 0; i < THREADS; i++)
1431 {
1432 threads[i]->join(threads[i]);
1433 ck_assert_int_eq(values[i], 0);
1434 }
1435 for (i = 0; i < countof(tls); i++)
1436 {
1437 tls[i]->destroy(tls[i]);
1438 }
1439 ck_assert_int_eq(main_value, 0);
1440}
1441END_TEST
1442
de42bf35
TB
1443Suite *threading_suite_create()
1444{
1445 Suite *s;
1446 TCase *tc;
1447
1448 s = suite_create("threading");
1449
1450 tc = tcase_create("recursive mutex");
1451 tcase_add_test(tc, test_mutex);
1452 suite_add_tcase(s, tc);
1453
b1bfe595
MW
1454 tc = tcase_create("spinlock");
1455 tcase_add_test(tc, test_spinlock);
1456 suite_add_tcase(s, tc);
1457
13183a74
MW
1458 tc = tcase_create("condvar");
1459 tcase_add_test(tc, test_condvar);
b7db393d 1460 tcase_add_test(tc, test_condvar_recursive);
9a0a891e 1461 tcase_add_test(tc, test_condvar_broad);
31f9f777 1462 tcase_add_test(tc, test_condvar_timed);
8699a32b 1463 tcase_add_test(tc, test_condvar_timed_abs);
8b25b5c3 1464 tcase_add_test(tc, test_condvar_cancel);
13183a74
MW
1465 suite_add_tcase(s, tc);
1466
dac31fe1
MW
1467 tc = tcase_create("rwlock");
1468 tcase_add_test(tc, test_rwlock);
6a3f0467 1469 tcase_add_test(tc, test_rwlock_try);
dac31fe1
MW
1470 suite_add_tcase(s, tc);
1471
f644b9e8
MW
1472 tc = tcase_create("rwlock condvar");
1473 tcase_add_test(tc, test_rwlock_condvar);
1032f52d 1474 tcase_add_test(tc, test_rwlock_condvar_broad);
af19213c 1475 tcase_add_test(tc, test_rwlock_condvar_timed);
b92c173b 1476 tcase_add_test(tc, test_rwlock_condvar_timed_abs);
478dc025 1477 tcase_add_test(tc, test_rwlock_condvar_cancel);
f644b9e8
MW
1478 suite_add_tcase(s, tc);
1479
ffab2e0c
MW
1480 tc = tcase_create("semaphore");
1481 tcase_add_test(tc, test_semaphore);
a14935ea 1482 tcase_add_test(tc, test_semaphore_timed);
fae1b852 1483 tcase_add_test(tc, test_semaphore_timed_abs);
a4cbda35 1484 tcase_add_test(tc, test_semaphore_cancel);
ffab2e0c
MW
1485 suite_add_tcase(s, tc);
1486
5d4a882f
MW
1487 tc = tcase_create("thread joining");
1488 tcase_add_test(tc, test_join);
c320c611 1489 tcase_add_test(tc, test_join_exit);
5d4a882f
MW
1490 suite_add_tcase(s, tc);
1491
274e6beb
MW
1492 tc = tcase_create("thread detaching");
1493 tcase_add_test(tc, test_detach);
c320c611 1494 tcase_add_test(tc, test_detach_exit);
274e6beb
MW
1495 suite_add_tcase(s, tc);
1496
855747ea
MW
1497 tc = tcase_create("thread cancellation");
1498 tcase_add_test(tc, test_cancel);
49e6848b 1499 tcase_add_test(tc, test_cancel_onoff);
e5b34086 1500 tcase_add_test(tc, test_cancel_point);
855747ea
MW
1501 suite_add_tcase(s, tc);
1502
4aec0c55
MW
1503 tc = tcase_create("thread cleanup");
1504 tcase_add_test(tc, test_cleanup);
1505 tcase_add_test(tc, test_cleanup_exit);
1506 tcase_add_test(tc, test_cleanup_cancel);
fd26b7ff 1507 tcase_add_test(tc, test_cleanup_pop);
4aec0c55
MW
1508 suite_add_tcase(s, tc);
1509
0b00e63e
MW
1510 tc = tcase_create("thread local storage");
1511 tcase_add_test(tc, test_tls);
21df9851 1512 tcase_add_test(tc, test_tls_cleanup);
0b00e63e
MW
1513 suite_add_tcase(s, tc);
1514
de42bf35
TB
1515 return s;
1516}