Annotation of embedaddon/strongswan/src/libstrongswan/tests/suites/test_threading.c, revision 1.1.1.2
1.1 misho 1: /*
2: * Copyright (C) 2013-2018 Tobias Brunner
3: * Copyright (C) 2008 Martin Willi
4: * HSR 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:
17: #include "test_suite.h"
18:
19: #include <unistd.h>
20:
21: #include <threading/thread.h>
22: #include <threading/mutex.h>
23: #include <threading/condvar.h>
24: #include <threading/rwlock.h>
25: #include <threading/rwlock_condvar.h>
26: #include <threading/spinlock.h>
27: #include <threading/semaphore.h>
28: #include <threading/thread_value.h>
29:
30: #ifdef WIN32
31: /* when running on AppVeyor the wait functions seem to frequently trigger a bit
32: * early, allow this if the difference is within 5ms. */
33: static inline void time_is_at_least(timeval_t *expected, timeval_t *actual)
34: {
35: if (!timercmp(actual, expected, >))
36: {
37: timeval_t diff;
38:
39: timersub(expected, actual, &diff);
40: if (!diff.tv_sec && diff.tv_usec <= 5000)
41: {
42: warn("allow timer event %dus too early on Windows (expected: %u.%u, "
43: "actual: %u.%u)", diff.tv_usec, expected->tv_sec,
44: expected->tv_usec, actual->tv_sec, actual->tv_usec);
45: return;
46: }
47: fail("expected: %u.%u, actual: %u.%u", expected->tv_sec,
48: expected->tv_usec, actual->tv_sec, actual->tv_usec);
49: }
50: }
51: #else /* WIN32 */
52: static inline void time_is_at_least(timeval_t *expected, timeval_t *actual)
53: {
54: ck_assert_msg(timercmp(actual, expected, >), "expected: %u.%u, actual: "
55: "%u.%u", expected->tv_sec, expected->tv_usec, actual->tv_sec,
56: actual->tv_usec);
57: }
58: #endif /* WIN32 */
59:
60: /*******************************************************************************
61: * recursive mutex test
62: */
63:
64: #define THREADS 20
65:
66: /**
67: * Thread barrier data
68: */
69: typedef struct {
70: mutex_t *mutex;
71: condvar_t *cond;
72: int count;
73: int current;
74: bool active;
75: } barrier_t;
76:
77: /**
78: * Create a thread barrier for count threads
79: */
80: static barrier_t* barrier_create(int count)
81: {
82: barrier_t *this;
83:
84: INIT(this,
85: .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
86: .cond = condvar_create(CONDVAR_TYPE_DEFAULT),
87: .count = count,
88: );
89:
90: return this;
91: }
92:
93: /**
94: * Destroy a thread barrier
95: */
96: static void barrier_destroy(barrier_t *this)
97: {
98: this->mutex->destroy(this->mutex);
99: this->cond->destroy(this->cond);
100: free(this);
101: }
102:
103: /**
104: * Wait to have configured number of threads in barrier
105: */
106: static bool barrier_wait(barrier_t *this)
107: {
108: bool winner = FALSE;
109:
110: this->mutex->lock(this->mutex);
111: if (!this->active)
112: { /* first, reset */
113: this->active = TRUE;
114: this->current = 0;
115: }
116:
117: this->current++;
118: while (this->current < this->count)
119: {
120: this->cond->wait(this->cond, this->mutex);
121: }
122: if (this->active)
123: { /* first, win */
124: winner = TRUE;
125: this->active = FALSE;
126: }
127: this->mutex->unlock(this->mutex);
128: this->cond->broadcast(this->cond);
129: sched_yield();
130:
131: return winner;
132: }
133:
134: /**
135: * Barrier for some tests
136: */
137: static barrier_t *barrier;
138:
139: /**
140: * A mutex for tests requiring one
141: */
142: static mutex_t *mutex;
143:
144: /**
145: * A condvar for tests requiring one
146: */
147: static condvar_t *condvar;
148:
149: /**
150: * A counter for signaling
151: */
152: static int sigcount;
153:
154: static void *mutex_run(void *data)
155: {
156: int locked = 0;
157: int i;
158:
159: /* wait for all threads before getting in action */
160: barrier_wait(barrier);
161:
162: for (i = 0; i < 100; i++)
163: {
164: mutex->lock(mutex);
165: mutex->lock(mutex);
166: mutex->lock(mutex);
167: locked++;
168: sched_yield();
169: if (locked > 1)
170: {
171: fail("two threads locked the mutex concurrently");
172: }
173: locked--;
174: mutex->unlock(mutex);
175: mutex->unlock(mutex);
176: mutex->unlock(mutex);
177: }
178: return NULL;
179: }
180:
181: START_TEST(test_mutex)
182: {
183: thread_t *threads[THREADS];
184: int i;
185:
186: barrier = barrier_create(THREADS);
187: mutex = mutex_create(MUTEX_TYPE_RECURSIVE);
188:
189: for (i = 0; i < 10; i++)
190: {
191: mutex->lock(mutex);
192: mutex->unlock(mutex);
193: }
194: for (i = 0; i < 10; i++)
195: {
196: mutex->lock(mutex);
197: }
198: for (i = 0; i < 10; i++)
199: {
200: mutex->unlock(mutex);
201: }
202:
203: for (i = 0; i < THREADS; i++)
204: {
205: threads[i] = thread_create(mutex_run, NULL);
206: }
207: for (i = 0; i < THREADS; i++)
208: {
209: threads[i]->join(threads[i]);
210: }
211:
212: mutex->destroy(mutex);
213: barrier_destroy(barrier);
214: }
215: END_TEST
216:
217: /**
218: * Spinlock for testing
219: */
220: static spinlock_t *spinlock;
221:
222: static void *spinlock_run(void *data)
223: {
224: int i, *locked = (int*)data;
225:
226: barrier_wait(barrier);
227:
228: for (i = 0; i < 1000; i++)
229: {
230: spinlock->lock(spinlock);
231: (*locked)++;
232: ck_assert_int_eq(*locked, 1);
233: (*locked)--;
234: spinlock->unlock(spinlock);
235: }
236: return NULL;
237: }
238:
239: START_TEST(test_spinlock)
240: {
241: thread_t *threads[THREADS];
242: int i, locked = 0;
243:
244: barrier = barrier_create(THREADS);
245: spinlock = spinlock_create();
246:
247: for (i = 0; i < THREADS; i++)
248: {
249: threads[i] = thread_create(spinlock_run, &locked);
250: }
251: for (i = 0; i < THREADS; i++)
252: {
253: threads[i]->join(threads[i]);
254: }
255:
256: spinlock->destroy(spinlock);
257: barrier_destroy(barrier);
258: }
259: END_TEST
260:
261: static void *condvar_run(void *data)
262: {
263: mutex->lock(mutex);
264: sigcount++;
265: condvar->signal(condvar);
266: mutex->unlock(mutex);
267: return NULL;
268: }
269:
270: START_TEST(test_condvar)
271: {
272: thread_t *threads[THREADS];
273: int i;
274:
275: mutex = mutex_create(MUTEX_TYPE_DEFAULT);
276: condvar = condvar_create(CONDVAR_TYPE_DEFAULT);
277: sigcount = 0;
278:
279: for (i = 0; i < THREADS; i++)
280: {
281: threads[i] = thread_create(condvar_run, NULL);
282: }
283:
284: mutex->lock(mutex);
285: while (sigcount < THREADS)
286: {
287: condvar->wait(condvar, mutex);
288: }
289: mutex->unlock(mutex);
290:
291: for (i = 0; i < THREADS; i++)
292: {
293: threads[i]->join(threads[i]);
294: }
295:
296: mutex->destroy(mutex);
297: condvar->destroy(condvar);
298: }
299: END_TEST
300:
301: static void *condvar_recursive_run(void *data)
302: {
303: mutex->lock(mutex);
304: mutex->lock(mutex);
305: mutex->lock(mutex);
306: sigcount++;
307: condvar->signal(condvar);
308: mutex->unlock(mutex);
309: mutex->unlock(mutex);
310: mutex->unlock(mutex);
311: return NULL;
312: }
313:
314: START_TEST(test_condvar_recursive)
315: {
316: thread_t *threads[THREADS];
317: int i;
318:
319: mutex = mutex_create(MUTEX_TYPE_RECURSIVE);
320: condvar = condvar_create(CONDVAR_TYPE_DEFAULT);
321: sigcount = 0;
322:
323: mutex->lock(mutex);
324:
325: for (i = 0; i < THREADS; i++)
326: {
327: threads[i] = thread_create(condvar_recursive_run, NULL);
328: }
329:
330: mutex->lock(mutex);
331: mutex->lock(mutex);
332: while (sigcount < THREADS)
333: {
334: condvar->wait(condvar, mutex);
335: }
336: mutex->unlock(mutex);
337: mutex->unlock(mutex);
338: mutex->unlock(mutex);
339:
340: for (i = 0; i < THREADS; i++)
341: {
342: threads[i]->join(threads[i]);
343: }
344:
345: mutex->destroy(mutex);
346: condvar->destroy(condvar);
347: }
348: END_TEST
349:
350: static void *condvar_run_broad(void *data)
351: {
352: mutex->lock(mutex);
353: while (sigcount < 0)
354: {
355: condvar->wait(condvar, mutex);
356: }
357: mutex->unlock(mutex);
358: return NULL;
359: }
360:
361: START_TEST(test_condvar_broad)
362: {
363: thread_t *threads[THREADS];
364: int i;
365:
366: mutex = mutex_create(MUTEX_TYPE_DEFAULT);
367: condvar = condvar_create(CONDVAR_TYPE_DEFAULT);
368: sigcount = 0;
369:
370: for (i = 0; i < THREADS; i++)
371: {
372: threads[i] = thread_create(condvar_run_broad, NULL);
373: }
374:
375: sched_yield();
376:
377: mutex->lock(mutex);
378: sigcount = 1;
379: condvar->broadcast(condvar);
380: mutex->unlock(mutex);
381:
382: for (i = 0; i < THREADS; i++)
383: {
384: threads[i]->join(threads[i]);
385: }
386:
387: mutex->destroy(mutex);
388: condvar->destroy(condvar);
389: }
390: END_TEST
391:
392: START_TEST(test_condvar_timed)
393: {
394: thread_t *thread;
395: timeval_t start, end, diff = { .tv_usec = 50000 };
396:
397: mutex = mutex_create(MUTEX_TYPE_DEFAULT);
398: condvar = condvar_create(CONDVAR_TYPE_DEFAULT);
399: sigcount = 0;
400:
401: mutex->lock(mutex);
402: while (TRUE)
403: {
404: time_monotonic(&start);
405: if (condvar->timed_wait(condvar, mutex, diff.tv_usec / 1000))
406: {
407: break;
408: }
409: }
410: time_monotonic(&end);
411: mutex->unlock(mutex);
412: timersub(&end, &start, &end);
413: time_is_at_least(&diff, &end);
414:
415: thread = thread_create(condvar_run, NULL);
416:
417: mutex->lock(mutex);
418: while (sigcount == 0)
419: {
420: ck_assert(!condvar->timed_wait(condvar, mutex, 1000));
421: }
422: mutex->unlock(mutex);
423:
424: thread->join(thread);
425: mutex->destroy(mutex);
426: condvar->destroy(condvar);
427: }
428: END_TEST
429:
430: START_TEST(test_condvar_timed_abs)
431: {
432: thread_t *thread;
433: timeval_t start, end, abso, diff = { .tv_usec = 50000 };
434:
435: mutex = mutex_create(MUTEX_TYPE_DEFAULT);
436: condvar = condvar_create(CONDVAR_TYPE_DEFAULT);
437: sigcount = 0;
438:
439: mutex->lock(mutex);
440: while (TRUE)
441: {
442: time_monotonic(&start);
443: timeradd(&start, &diff, &abso);
444: if (condvar->timed_wait_abs(condvar, mutex, abso))
445: {
446: break;
447: }
448: }
449: time_monotonic(&end);
450: mutex->unlock(mutex);
451: time_is_at_least(&diff, &end);
452:
453: thread = thread_create(condvar_run, NULL);
454:
455: time_monotonic(&start);
456: diff.tv_sec = 1;
457: timeradd(&start, &diff, &abso);
458: mutex->lock(mutex);
459: while (sigcount == 0)
460: {
461: ck_assert(!condvar->timed_wait_abs(condvar, mutex, abso));
462: }
463: mutex->unlock(mutex);
464:
465: thread->join(thread);
466: mutex->destroy(mutex);
467: condvar->destroy(condvar);
468: }
469: END_TEST
470:
471: static void *condvar_cancel_run(void *data)
472: {
473: thread_cancelability(FALSE);
474:
475: mutex->lock(mutex);
476:
477: sigcount++;
478: condvar->broadcast(condvar);
479:
480: thread_cleanup_push((void*)mutex->unlock, mutex);
481: thread_cancelability(TRUE);
482: while (TRUE)
483: {
484: condvar->wait(condvar, mutex);
485: }
486: thread_cleanup_pop(TRUE);
487:
488: return NULL;
489: }
490:
491: START_TEST(test_condvar_cancel)
492: {
493: thread_t *threads[THREADS];
494: int i;
495:
496: mutex = mutex_create(MUTEX_TYPE_DEFAULT);
497: condvar = condvar_create(CONDVAR_TYPE_DEFAULT);
498: sigcount = 0;
499:
500: for (i = 0; i < THREADS; i++)
501: {
502: threads[i] = thread_create(condvar_cancel_run, NULL);
503: }
504:
505: /* wait for all threads */
506: mutex->lock(mutex);
507: while (sigcount < THREADS)
508: {
509: condvar->wait(condvar, mutex);
510: }
511: mutex->unlock(mutex);
512:
513: for (i = 0; i < THREADS; i++)
514: {
515: threads[i]->cancel(threads[i]);
516: }
517: for (i = 0; i < THREADS; i++)
518: {
519: threads[i]->join(threads[i]);
520: }
521:
522: mutex->destroy(mutex);
523: condvar->destroy(condvar);
524: }
525: END_TEST
526:
527: /**
528: * RWlock for different tests
529: */
530: static rwlock_t *rwlock;
531:
532: static void *rwlock_run(refcount_t *refs)
533: {
534: rwlock->read_lock(rwlock);
535: ref_get(refs);
536: sched_yield();
537: ignore_result(ref_put(refs));
538: rwlock->unlock(rwlock);
539:
540: if (rwlock->try_write_lock(rwlock))
541: {
542: ck_assert_int_eq(*refs, 0);
543: sched_yield();
544: rwlock->unlock(rwlock);
545: }
546:
547: rwlock->write_lock(rwlock);
548: ck_assert_int_eq(*refs, 0);
549: sched_yield();
550: rwlock->unlock(rwlock);
551:
552: rwlock->read_lock(rwlock);
553: rwlock->read_lock(rwlock);
554: ref_get(refs);
555: sched_yield();
556: ignore_result(ref_put(refs));
557: rwlock->unlock(rwlock);
558: rwlock->unlock(rwlock);
559:
560: return NULL;
561: }
562:
563: START_TEST(test_rwlock)
564: {
565: thread_t *threads[THREADS];
566: refcount_t refs = 0;
567: int i;
568:
569: rwlock = rwlock_create(RWLOCK_TYPE_DEFAULT);
570:
571: for (i = 0; i < THREADS; i++)
572: {
573: threads[i] = thread_create((void*)rwlock_run, &refs);
574: }
575: for (i = 0; i < THREADS; i++)
576: {
577: threads[i]->join(threads[i]);
578: }
579:
580: rwlock->destroy(rwlock);
581: }
582: END_TEST
583:
584: static void *rwlock_try_run(void *param)
585: {
586: if (rwlock->try_write_lock(rwlock))
587: {
588: rwlock->unlock(rwlock);
589: return param;
590: }
591: return NULL;
592: }
593:
594: START_TEST(test_rwlock_try)
595: {
596: uintptr_t magic = 0xcafebabe;
597: thread_t *thread;
598:
599: rwlock = rwlock_create(RWLOCK_TYPE_DEFAULT);
600:
601: thread = thread_create(rwlock_try_run, (void*)magic);
602: ck_assert_int_eq((uintptr_t)thread->join(thread), magic);
603:
604: rwlock->read_lock(rwlock);
605: thread = thread_create(rwlock_try_run, (void*)magic);
606: ck_assert(thread->join(thread) == NULL);
607: rwlock->unlock(rwlock);
608:
609: rwlock->read_lock(rwlock);
610: rwlock->read_lock(rwlock);
611: rwlock->read_lock(rwlock);
612: thread = thread_create(rwlock_try_run, (void*)magic);
613: ck_assert(thread->join(thread) == NULL);
614: rwlock->unlock(rwlock);
615: rwlock->unlock(rwlock);
616: rwlock->unlock(rwlock);
617:
618: rwlock->write_lock(rwlock);
619: thread = thread_create(rwlock_try_run, (void*)magic);
620: ck_assert(thread->join(thread) == NULL);
621: rwlock->unlock(rwlock);
622:
623: rwlock->destroy(rwlock);
624: }
625: END_TEST
626:
627: /**
628: * Rwlock condvar
629: */
630: static rwlock_condvar_t *rwcond;
631:
632: static void *rwlock_condvar_run(void *data)
633: {
634: rwlock->write_lock(rwlock);
635: sigcount++;
636: rwcond->signal(rwcond);
637: rwlock->unlock(rwlock);
638: return NULL;
639: }
640:
641: START_TEST(test_rwlock_condvar)
642: {
643: thread_t *threads[THREADS];
644: int i;
645:
646: rwlock = rwlock_create(RWLOCK_TYPE_DEFAULT);
647: rwcond = rwlock_condvar_create();
648: sigcount = 0;
649:
650: for (i = 0; i < THREADS; i++)
651: {
652: threads[i] = thread_create(rwlock_condvar_run, NULL);
653: }
654:
655: rwlock->write_lock(rwlock);
656: while (sigcount < THREADS)
657: {
658: rwcond->wait(rwcond, rwlock);
659: }
660: rwlock->unlock(rwlock);
661:
662: for (i = 0; i < THREADS; i++)
663: {
664: threads[i]->join(threads[i]);
665: }
666:
667: rwlock->destroy(rwlock);
668: rwcond->destroy(rwcond);
669: }
670: END_TEST
671:
672: static void *rwlock_condvar_run_broad(void *data)
673: {
674: rwlock->write_lock(rwlock);
675: while (sigcount < 0)
676: {
677: rwcond->wait(rwcond, rwlock);
678: }
679: rwlock->unlock(rwlock);
680: return NULL;
681: }
682:
683: START_TEST(test_rwlock_condvar_broad)
684: {
685: thread_t *threads[THREADS];
686: int i;
687:
688: rwlock = rwlock_create(RWLOCK_TYPE_DEFAULT);
689: rwcond = rwlock_condvar_create();
690: sigcount = 0;
691:
692: for (i = 0; i < THREADS; i++)
693: {
694: threads[i] = thread_create(rwlock_condvar_run_broad, NULL);
695: }
696:
697: sched_yield();
698:
699: rwlock->write_lock(rwlock);
700: sigcount = 1;
701: rwcond->broadcast(rwcond);
702: rwlock->unlock(rwlock);
703:
704: for (i = 0; i < THREADS; i++)
705: {
706: threads[i]->join(threads[i]);
707: }
708:
709: rwlock->destroy(rwlock);
710: rwcond->destroy(rwcond);
711: }
712: END_TEST
713:
714: START_TEST(test_rwlock_condvar_timed)
715: {
716: thread_t *thread;
717: timeval_t start, end, diff = { .tv_usec = 50000 };
718:
719: rwlock = rwlock_create(RWLOCK_TYPE_DEFAULT);
720: rwcond = rwlock_condvar_create();
721: sigcount = 0;
722:
723: rwlock->write_lock(rwlock);
724: while (TRUE)
725: {
726: time_monotonic(&start);
727: if (rwcond->timed_wait(rwcond, rwlock, diff.tv_usec / 1000))
728: {
729: break;
730: }
731: }
732: rwlock->unlock(rwlock);
733: time_monotonic(&end);
734: timersub(&end, &start, &end);
735: time_is_at_least(&diff, &end);
736:
737: thread = thread_create(rwlock_condvar_run, NULL);
738:
739: rwlock->write_lock(rwlock);
740: while (sigcount == 0)
741: {
742: ck_assert(!rwcond->timed_wait(rwcond, rwlock, 1000));
743: }
744: rwlock->unlock(rwlock);
745:
746: thread->join(thread);
747: rwlock->destroy(rwlock);
748: rwcond->destroy(rwcond);
749: }
750: END_TEST
751:
752: START_TEST(test_rwlock_condvar_timed_abs)
753: {
754: thread_t *thread;
755: timeval_t start, end, abso, diff = { .tv_usec = 50000 };
756:
757: rwlock = rwlock_create(RWLOCK_TYPE_DEFAULT);
758: rwcond = rwlock_condvar_create();
759: sigcount = 0;
760:
761: rwlock->write_lock(rwlock);
762: while (TRUE)
763: {
764: time_monotonic(&start);
765: timeradd(&start, &diff, &abso);
766: if (rwcond->timed_wait_abs(rwcond, rwlock, abso))
767: {
768: break;
769: }
770: }
771: rwlock->unlock(rwlock);
772: time_monotonic(&end);
773: time_is_at_least(&abso, &end);
774:
775: thread = thread_create(rwlock_condvar_run, NULL);
776:
777: time_monotonic(&start);
778: diff.tv_sec = 1;
779: timeradd(&start, &diff, &abso);
780: rwlock->write_lock(rwlock);
781: while (sigcount == 0)
782: {
783: ck_assert(!rwcond->timed_wait_abs(rwcond, rwlock, abso));
784: }
785: rwlock->unlock(rwlock);
786:
787: thread->join(thread);
788: rwlock->destroy(rwlock);
789: rwcond->destroy(rwcond);
790: }
791: END_TEST
792:
793: static void *rwlock_condvar_cancel_run(void *data)
794: {
795: thread_cancelability(FALSE);
796:
797: rwlock->write_lock(rwlock);
798:
799: sigcount++;
800: rwcond->broadcast(rwcond);
801:
802: thread_cleanup_push((void*)rwlock->unlock, rwlock);
803: thread_cancelability(TRUE);
804: while (TRUE)
805: {
806: rwcond->wait(rwcond, rwlock);
807: }
808: thread_cleanup_pop(TRUE);
809:
810: return NULL;
811: }
812:
813: START_TEST(test_rwlock_condvar_cancel)
814: {
815: thread_t *threads[THREADS];
816: int i;
817:
818: rwlock = rwlock_create(RWLOCK_TYPE_DEFAULT);
819: rwcond = rwlock_condvar_create();
820: sigcount = 0;
821:
822: for (i = 0; i < THREADS; i++)
823: {
824: threads[i] = thread_create(rwlock_condvar_cancel_run, NULL);
825: }
826:
827: /* wait for all threads */
828: rwlock->write_lock(rwlock);
829: while (sigcount < THREADS)
830: {
831: rwcond->wait(rwcond, rwlock);
832: }
833: rwlock->unlock(rwlock);
834:
835: for (i = 0; i < THREADS; i++)
836: {
837: threads[i]->cancel(threads[i]);
838: }
839: for (i = 0; i < THREADS; i++)
840: {
841: threads[i]->join(threads[i]);
842: }
843:
844: rwlock->destroy(rwlock);
845: rwcond->destroy(rwcond);
846: }
847: END_TEST
848:
849: /**
850: * Semaphore for different tests
851: */
852: static semaphore_t *semaphore;
853:
854: static void *semaphore_run(void *data)
855: {
856: semaphore->post(semaphore);
857: return NULL;
858: }
859:
860: START_TEST(test_semaphore)
861: {
862: thread_t *threads[THREADS];
863: int i, initial = 5;
864:
865: semaphore = semaphore_create(initial);
866:
867: for (i = 0; i < THREADS; i++)
868: {
869: threads[i] = thread_create(semaphore_run, NULL);
870: }
871: for (i = 0; i < THREADS + initial; i++)
872: {
873: semaphore->wait(semaphore);
874: }
875: for (i = 0; i < THREADS; i++)
876: {
877: threads[i]->join(threads[i]);
878: }
879:
880: semaphore->destroy(semaphore);
881: }
882: END_TEST
883:
884: START_TEST(test_semaphore_timed)
885: {
886: thread_t *thread;
887: timeval_t start, end, diff = { .tv_usec = 50000 };
888:
889: semaphore = semaphore_create(0);
890:
891: time_monotonic(&start);
892: ck_assert(semaphore->timed_wait(semaphore, diff.tv_usec / 1000));
893: time_monotonic(&end);
894: timersub(&end, &start, &end);
895: time_is_at_least(&diff, &end);
896:
897: thread = thread_create(semaphore_run, NULL);
898:
899: ck_assert(!semaphore->timed_wait(semaphore, 1000));
900:
901: thread->join(thread);
902: semaphore->destroy(semaphore);
903: }
904: END_TEST
905:
906: START_TEST(test_semaphore_timed_abs)
907: {
908: thread_t *thread;
909: timeval_t start, end, abso, diff = { .tv_usec = 50000 };
910:
911: semaphore = semaphore_create(0);
912:
913: time_monotonic(&start);
914: timeradd(&start, &diff, &abso);
915: ck_assert(semaphore->timed_wait_abs(semaphore, abso));
916: time_monotonic(&end);
917: time_is_at_least(&abso, &end);
918:
919: thread = thread_create(semaphore_run, NULL);
920:
921: time_monotonic(&start);
922: diff.tv_sec = 1;
923: timeradd(&start, &diff, &abso);
924: ck_assert(!semaphore->timed_wait_abs(semaphore, abso));
925:
926: thread->join(thread);
927: semaphore->destroy(semaphore);
928: }
929: END_TEST
930:
931: static void *semaphore_cancel_run(void *data)
932: {
933: refcount_t *ready = (refcount_t*)data;
934:
935: thread_cancelability(FALSE);
936: ref_get(ready);
937:
938: thread_cancelability(TRUE);
939: semaphore->wait(semaphore);
940:
941: ck_assert(FALSE);
942: return NULL;
943: }
944:
945: START_TEST(test_semaphore_cancel)
946: {
947: thread_t *threads[THREADS];
948: refcount_t ready = 0;
949: int i;
950:
951: semaphore = semaphore_create(0);
952:
953: for (i = 0; i < THREADS; i++)
954: {
955: threads[i] = thread_create(semaphore_cancel_run, &ready);
956: }
957: while (ready < THREADS)
958: {
959: sched_yield();
960: }
961: for (i = 0; i < THREADS; i++)
962: {
963: threads[i]->cancel(threads[i]);
964: }
965: for (i = 0; i < THREADS; i++)
966: {
967: threads[i]->join(threads[i]);
968: }
969:
970: semaphore->destroy(semaphore);
971: }
972: END_TEST
973:
974: static void *join_run(void *data)
975: {
976: /* force some context switches */
977: sched_yield();
978: return (void*)((uintptr_t)data + THREADS);
979: }
980:
981: START_TEST(test_join)
982: {
983: thread_t *threads[THREADS];
984: int i;
985:
986: for (i = 0; i < THREADS; i++)
987: {
988: threads[i] = thread_create(join_run, (void*)(uintptr_t)i);
989: }
990: for (i = 0; i < THREADS; i++)
991: {
992: ck_assert_int_eq((uintptr_t)threads[i]->join(threads[i]), i + THREADS);
993: }
994: }
995: END_TEST
996:
997: static void *exit_join_run(void *data)
998: {
999: sched_yield();
1000: thread_exit((void*)((uintptr_t)data + THREADS));
1001: /* not reached */
1002: ck_assert(FALSE);
1003: return NULL;
1004: }
1005:
1006: START_TEST(test_join_exit)
1007: {
1008: thread_t *threads[THREADS];
1009: int i;
1010:
1011: for (i = 0; i < THREADS; i++)
1012: {
1013: threads[i] = thread_create(exit_join_run, (void*)(uintptr_t)i);
1014: }
1015: for (i = 0; i < THREADS; i++)
1016: {
1017: ck_assert_int_eq((uintptr_t)threads[i]->join(threads[i]), i + THREADS);
1018: }
1019: }
1020: END_TEST
1021:
1022: static void *detach_run(void *data)
1023: {
1024: refcount_t *running = (refcount_t*)data;
1025:
1026: ignore_result(ref_put(running));
1027: return NULL;
1028: }
1029:
1030: START_TEST(test_detach)
1031: {
1032: thread_t *threads[THREADS];
1033: int i;
1034: refcount_t running = 0;
1035:
1036: for (i = 0; i < THREADS; i++)
1037: {
1038: ref_get(&running);
1039: threads[i] = thread_create(detach_run, &running);
1040: }
1041: for (i = 0; i < THREADS; i++)
1042: {
1043: threads[i]->detach(threads[i]);
1044: }
1045: while (running > 0)
1046: {
1047: sched_yield();
1048: }
1049: /* no checks done here, but we check that thread state gets cleaned
1050: * up with leak detective. give the threads time to clean up. */
1051: usleep(10000);
1052: }
1053: END_TEST
1054:
1055: static void *detach_exit_run(void *data)
1056: {
1057: refcount_t *running = (refcount_t*)data;
1058:
1059: ignore_result(ref_put(running));
1060: thread_exit(NULL);
1061: /* not reached */
1062: ck_assert(FALSE);
1063: return NULL;
1064: }
1065:
1066: START_TEST(test_detach_exit)
1067: {
1068: thread_t *threads[THREADS];
1069: int i;
1070: refcount_t running = 0;
1071:
1072: for (i = 0; i < THREADS; i++)
1073: {
1074: ref_get(&running);
1075: threads[i] = thread_create(detach_exit_run, &running);
1076: }
1077: for (i = 0; i < THREADS; i++)
1078: {
1079: threads[i]->detach(threads[i]);
1080: }
1081: while (running > 0)
1082: {
1083: sched_yield();
1084: }
1085: /* no checks done here, but we check that thread state gets cleaned
1086: * up with leak detective. give the threads time to clean up. */
1087: usleep(10000);
1088: }
1089: END_TEST
1090:
1091: static void *cancel_run(void *data)
1092: {
1093: /* default cancelability should be TRUE, so don't change it */
1094: while (TRUE)
1095: {
1096: sleep(10);
1097: }
1098: return NULL;
1099: }
1100:
1101: START_TEST(test_cancel)
1102: {
1103: thread_t *threads[THREADS];
1104: int i;
1105:
1106: for (i = 0; i < THREADS; i++)
1107: {
1108: threads[i] = thread_create(cancel_run, NULL);
1109: }
1110: for (i = 0; i < THREADS; i++)
1111: {
1112: threads[i]->cancel(threads[i]);
1113: }
1114: for (i = 0; i < THREADS; i++)
1115: {
1116: threads[i]->join(threads[i]);
1117: }
1118: }
1119: END_TEST
1120:
1.1.1.2 ! misho 1121: typedef struct {
! 1122: semaphore_t *sem;
! 1123: bool cancellable;
! 1124: } cancel_onoff_data_t;
! 1125:
! 1126: static void *cancel_onoff_run(void *data_in)
1.1 misho 1127: {
1.1.1.2 ! misho 1128: cancel_onoff_data_t *data = (cancel_onoff_data_t*)data_in;
1.1 misho 1129:
1130: thread_cancelability(FALSE);
1.1.1.2 ! misho 1131: data->cancellable = FALSE;
1.1 misho 1132:
1133: /* we should not get cancelled here */
1.1.1.2 ! misho 1134: data->sem->wait(data->sem);
1.1 misho 1135:
1.1.1.2 ! misho 1136: data->cancellable = TRUE;
1.1 misho 1137: thread_cancelability(TRUE);
1138:
1139: /* but here */
1140: while (TRUE)
1141: {
1142: sleep(10);
1143: }
1144: return NULL;
1145: }
1146:
1147: START_TEST(test_cancel_onoff)
1148: {
1149: thread_t *threads[THREADS];
1.1.1.2 ! misho 1150: cancel_onoff_data_t data[THREADS];
! 1151: semaphore_t *sem;
1.1 misho 1152: int i;
1153:
1.1.1.2 ! misho 1154: sem = semaphore_create(0);
1.1 misho 1155: for (i = 0; i < THREADS; i++)
1156: {
1.1.1.2 ! misho 1157: data[i].sem = sem;
! 1158: data[i].cancellable = TRUE;
! 1159: threads[i] = thread_create(cancel_onoff_run, &data[i]);
1.1 misho 1160: /* wait until thread has cleared its cancelability */
1.1.1.2 ! misho 1161: while (data[i].cancellable)
1.1 misho 1162: {
1163: sched_yield();
1164: }
1.1.1.2 ! misho 1165: }
! 1166: for (i = 0; i < THREADS; i++)
! 1167: {
1.1 misho 1168: threads[i]->cancel(threads[i]);
1169: }
1.1.1.2 ! misho 1170: /* let all threads continue */
! 1171: for (i = 0; i < THREADS; i++)
! 1172: {
! 1173: sem->post(sem);
! 1174: }
1.1 misho 1175: for (i = 0; i < THREADS; i++)
1176: {
1177: threads[i]->join(threads[i]);
1.1.1.2 ! misho 1178: ck_assert(data[i].cancellable);
1.1 misho 1179: }
1.1.1.2 ! misho 1180: sem->destroy(sem);
1.1 misho 1181: }
1182: END_TEST
1183:
1184: static void *cancel_point_run(void *data)
1185: {
1186: thread_cancelability(FALSE);
1187: while (TRUE)
1188: {
1189: /* implicitly enables cancelability */
1190: thread_cancellation_point();
1191: }
1192: return NULL;
1193: }
1194:
1195: START_TEST(test_cancel_point)
1196: {
1197: thread_t *threads[THREADS];
1198: int i;
1199:
1200: for (i = 0; i < THREADS; i++)
1201: {
1202: threads[i] = thread_create(cancel_point_run, NULL);
1203: }
1204: sched_yield();
1205: for (i = 0; i < THREADS; i++)
1206: {
1207: threads[i]->cancel(threads[i]);
1208: }
1209: for (i = 0; i < THREADS; i++)
1210: {
1211: threads[i]->join(threads[i]);
1212: }
1213: }
1214: END_TEST
1215:
1216: static void close_fd_ptr(void *fd)
1217: {
1218: close(*(int*)fd);
1219: }
1220:
1221: static void cancellation_recv()
1222: {
1223: int sv[2];
1224: char buf[1];
1225:
1226: ck_assert(socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == 0);
1227:
1228: thread_cleanup_push(close_fd_ptr, &sv[0]);
1229: thread_cleanup_push(close_fd_ptr, &sv[1]);
1230:
1231: thread_cancelability(TRUE);
1232: while (TRUE)
1233: {
1234: ck_assert(recv(sv[0], buf, sizeof(buf), 0) == 1);
1235: }
1236: }
1237:
1238: static void cancellation_read()
1239: {
1240: int sv[2];
1241: char buf[1];
1242:
1243: ck_assert(socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == 0);
1244:
1245: thread_cleanup_push(close_fd_ptr, &sv[0]);
1246: thread_cleanup_push(close_fd_ptr, &sv[1]);
1247:
1248: thread_cancelability(TRUE);
1249: while (TRUE)
1250: {
1251: ck_assert(read(sv[0], buf, sizeof(buf)) == 1);
1252: }
1253: }
1254:
1255: static void cancellation_select()
1256: {
1257: int sv[2];
1258: fd_set set;
1259:
1260: ck_assert(socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == 0);
1261:
1262: thread_cleanup_push(close_fd_ptr, &sv[0]);
1263: thread_cleanup_push(close_fd_ptr, &sv[1]);
1264:
1265: FD_ZERO(&set);
1266: FD_SET(sv[0], &set);
1267: thread_cancelability(TRUE);
1268: while (TRUE)
1269: {
1270: ck_assert(select(sv[0] + 1, &set, NULL, NULL, NULL) == 1);
1271: }
1272: }
1273:
1274: static void cancellation_poll()
1275: {
1276: int sv[2];
1277: struct pollfd pfd;
1278:
1279: ck_assert(socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == 0);
1280:
1281: thread_cleanup_push(close_fd_ptr, &sv[0]);
1282: thread_cleanup_push(close_fd_ptr, &sv[1]);
1283:
1284: pfd.fd = sv[0];
1285: pfd.events = POLLIN;
1286: thread_cancelability(TRUE);
1287: while (TRUE)
1288: {
1289: ck_assert(poll(&pfd, 1, -1) == 1);
1290: }
1291: }
1292:
1293: static void cancellation_accept()
1294: {
1295: host_t *host;
1296: int fd, c;
1297:
1298: fd = socket(AF_INET, SOCK_STREAM, 0);
1299: ck_assert(fd >= 0);
1300: host = host_create_from_string("127.0.0.1", 0);
1301: ck_assert_msg(bind(fd, host->get_sockaddr(host),
1302: *host->get_sockaddr_len(host)) == 0, "%m");
1303: host->destroy(host);
1304: ck_assert(listen(fd, 5) == 0);
1305:
1306: thread_cleanup_push(close_fd_ptr, &fd);
1307:
1308: thread_cancelability(TRUE);
1309: while (TRUE)
1310: {
1311: c = accept(fd, NULL, NULL);
1312: ck_assert(c >= 0);
1313: close(c);
1314: }
1315: }
1316:
1317: static void cancellation_cond()
1318: {
1319: mutex_t *mutex;
1320: condvar_t *cond;
1321:
1322: mutex = mutex_create(MUTEX_TYPE_DEFAULT);
1323: cond = condvar_create(CONDVAR_TYPE_DEFAULT);
1324: mutex->lock(mutex);
1325:
1326: thread_cleanup_push((void*)mutex->destroy, mutex);
1327: thread_cleanup_push((void*)cond->destroy, cond);
1328:
1329: thread_cancelability(TRUE);
1330: while (TRUE)
1331: {
1332: cond->wait(cond, mutex);
1333: }
1334: }
1335:
1336: static void cancellation_rwcond()
1337: {
1338: rwlock_t *lock;
1339: rwlock_condvar_t *cond;
1340:
1341: lock = rwlock_create(RWLOCK_TYPE_DEFAULT);
1342: cond = rwlock_condvar_create();
1343: lock->write_lock(lock);
1344:
1345: thread_cleanup_push((void*)lock->destroy, lock);
1346: thread_cleanup_push((void*)cond->destroy, cond);
1347:
1348: thread_cancelability(TRUE);
1349: while (TRUE)
1350: {
1351: cond->wait(cond, lock);
1352: }
1353: }
1354:
1355: static void (*cancellation_points[])() = {
1356: cancellation_read,
1357: cancellation_recv,
1358: cancellation_select,
1359: cancellation_poll,
1360: cancellation_accept,
1361: cancellation_cond,
1362: cancellation_rwcond,
1363: };
1364:
1365: static void* run_cancellation_point(void (*fn)())
1366: {
1367: fn();
1368: return NULL;
1369: }
1370:
1371: static void* run_cancellation_point_pre(void (*fn)())
1372: {
1373: usleep(5000);
1374: fn();
1375: return NULL;
1376: }
1377:
1378: START_TEST(test_cancellation_point)
1379: {
1380: thread_t *thread;
1381:
1382: thread = thread_create((void*)run_cancellation_point,
1383: cancellation_points[_i]);
1384: usleep(5000);
1385: thread->cancel(thread);
1386: thread->join(thread);
1387: }
1388: END_TEST
1389:
1390: START_TEST(test_cancellation_point_pre)
1391: {
1392: thread_t *thread;
1393:
1394: thread = thread_create((void*)run_cancellation_point_pre,
1395: cancellation_points[_i]);
1396: thread->cancel(thread);
1397: thread->join(thread);
1398: }
1399: END_TEST
1400:
1401: static void cleanup1(void *data)
1402: {
1403: uintptr_t *value = (uintptr_t*)data;
1404:
1405: ck_assert_int_eq(*value, 1);
1406: (*value)++;
1407: }
1408:
1409: static void cleanup2(void *data)
1410: {
1411: uintptr_t *value = (uintptr_t*)data;
1412:
1413: ck_assert_int_eq(*value, 2);
1414: (*value)++;
1415: }
1416:
1417: static void cleanup3(void *data)
1418: {
1419: uintptr_t *value = (uintptr_t*)data;
1420:
1421: ck_assert_int_eq(*value, 3);
1422: (*value)++;
1423: }
1424:
1425: static void *cleanup_run(void *data)
1426: {
1427: thread_cleanup_push(cleanup3, data);
1428: thread_cleanup_push(cleanup2, data);
1429: thread_cleanup_push(cleanup1, data);
1430: return NULL;
1431: }
1432:
1433: START_TEST(test_cleanup)
1434: {
1435: thread_t *threads[THREADS];
1436: uintptr_t values[THREADS];
1437: int i;
1438:
1439: for (i = 0; i < THREADS; i++)
1440: {
1441: values[i] = 1;
1442: threads[i] = thread_create(cleanup_run, &values[i]);
1443: }
1444: for (i = 0; i < THREADS; i++)
1445: {
1446: threads[i]->join(threads[i]);
1447: ck_assert_int_eq(values[i], 4);
1448: }
1449: }
1450: END_TEST
1451:
1452: static void *cleanup_exit_run(void *data)
1453: {
1454: thread_cleanup_push(cleanup3, data);
1455: thread_cleanup_push(cleanup2, data);
1456: thread_cleanup_push(cleanup1, data);
1457: thread_exit(NULL);
1458: ck_assert(FALSE);
1459: return NULL;
1460: }
1461:
1462: START_TEST(test_cleanup_exit)
1463: {
1464: thread_t *threads[THREADS];
1465: uintptr_t values[THREADS];
1466: int i;
1467:
1468: for (i = 0; i < THREADS; i++)
1469: {
1470: values[i] = 1;
1471: threads[i] = thread_create(cleanup_exit_run, &values[i]);
1472: }
1473: for (i = 0; i < THREADS; i++)
1474: {
1475: threads[i]->join(threads[i]);
1476: ck_assert_int_eq(values[i], 4);
1477: }
1478: }
1479: END_TEST
1480:
1481: static void *cleanup_cancel_run(void *data)
1482: {
1483: thread_cancelability(FALSE);
1484:
1485: barrier_wait(barrier);
1486:
1487: thread_cleanup_push(cleanup3, data);
1488: thread_cleanup_push(cleanup2, data);
1489: thread_cleanup_push(cleanup1, data);
1490:
1491: thread_cancelability(TRUE);
1492:
1493: while (TRUE)
1494: {
1495: sleep(1);
1496: }
1497: return NULL;
1498: }
1499:
1500: START_TEST(test_cleanup_cancel)
1501: {
1502: thread_t *threads[THREADS];
1503: uintptr_t values[THREADS];
1504: int i;
1505:
1506: barrier = barrier_create(THREADS+1);
1507: for (i = 0; i < THREADS; i++)
1508: {
1509: values[i] = 1;
1510: threads[i] = thread_create(cleanup_cancel_run, &values[i]);
1511: }
1512: barrier_wait(barrier);
1513: for (i = 0; i < THREADS; i++)
1514: {
1515: threads[i]->cancel(threads[i]);
1516: }
1517: for (i = 0; i < THREADS; i++)
1518: {
1519: threads[i]->join(threads[i]);
1520: ck_assert_int_eq(values[i], 4);
1521: }
1522: barrier_destroy(barrier);
1523: }
1524: END_TEST
1525:
1526: static void *cleanup_pop_run(void *data)
1527: {
1528: thread_cleanup_push(cleanup3, data);
1529: thread_cleanup_push(cleanup2, data);
1530: thread_cleanup_push(cleanup1, data);
1531:
1532: thread_cleanup_push(cleanup2, data);
1533: thread_cleanup_pop(FALSE);
1534:
1535: thread_cleanup_pop(TRUE);
1536: return NULL;
1537: }
1538:
1539: START_TEST(test_cleanup_pop)
1540: {
1541: thread_t *threads[THREADS];
1542: uintptr_t values[THREADS];
1543: int i;
1544:
1545: for (i = 0; i < THREADS; i++)
1546: {
1547: values[i] = 1;
1548: threads[i] = thread_create(cleanup_pop_run, &values[i]);
1549: }
1550: for (i = 0; i < THREADS; i++)
1551: {
1552: threads[i]->join(threads[i]);
1553: ck_assert_int_eq(values[i], 4);
1554: }
1555: }
1556: END_TEST
1557:
1558: static void *cleanup_popall_run(void *data)
1559: {
1560: thread_cleanup_push(cleanup3, data);
1561: thread_cleanup_push(cleanup2, data);
1562: thread_cleanup_push(cleanup1, data);
1563:
1564: thread_cleanup_popall();
1565: return NULL;
1566: }
1567:
1568: START_TEST(test_cleanup_popall)
1569: {
1570: thread_t *threads[THREADS];
1571: uintptr_t values[THREADS];
1572: int i;
1573:
1574: for (i = 0; i < THREADS; i++)
1575: {
1576: values[i] = 1;
1577: threads[i] = thread_create(cleanup_popall_run, &values[i]);
1578: }
1579: for (i = 0; i < THREADS; i++)
1580: {
1581: threads[i]->join(threads[i]);
1582: ck_assert_int_eq(values[i], 4);
1583: }
1584: }
1585: END_TEST
1586:
1587:
1588: static thread_value_t *tls[10];
1589:
1590: static void *tls_run(void *data)
1591: {
1592: uintptr_t value = (uintptr_t)data;
1593: int i, j;
1594:
1595: for (i = 0; i < countof(tls); i++)
1596: {
1597: ck_assert(tls[i]->get(tls[i]) == NULL);
1598: }
1599: for (i = 0; i < countof(tls); i++)
1600: {
1601: tls[i]->set(tls[i], (void*)(value * i));
1602: }
1603: for (j = 0; j < 1000; j++)
1604: {
1605: for (i = 0; i < countof(tls); i++)
1606: {
1607: tls[i]->set(tls[i], (void*)(value * i));
1608: ck_assert(tls[i]->get(tls[i]) == (void*)(value * i));
1609: }
1610: sched_yield();
1611: }
1612: for (i = 0; i < countof(tls); i++)
1613: {
1614: ck_assert(tls[i]->get(tls[i]) == (void*)(value * i));
1615: }
1616: return (void*)(value + 1);
1617: }
1618:
1619: START_TEST(test_tls)
1620: {
1621: thread_t *threads[THREADS];
1622: int i;
1623:
1624: for (i = 0; i < countof(tls); i++)
1625: {
1626: tls[i] = thread_value_create(NULL);
1627: }
1628: for (i = 0; i < THREADS; i++)
1629: {
1630: threads[i] = thread_create(tls_run, (void*)(uintptr_t)i);
1631: }
1632:
1633: ck_assert_int_eq((uintptr_t)tls_run((void*)(uintptr_t)(THREADS + 1)),
1634: THREADS + 2);
1635:
1636: for (i = 0; i < THREADS; i++)
1637: {
1638: ck_assert_int_eq((uintptr_t)threads[i]->join(threads[i]), i + 1);
1639: }
1640: for (i = 0; i < countof(tls); i++)
1641: {
1642: tls[i]->destroy(tls[i]);
1643: }
1644: }
1645: END_TEST
1646:
1647: static void tls_cleanup(void *data)
1648: {
1649: uintptr_t *value = (uintptr_t*)data;
1650:
1651: (*value)--;
1652: }
1653:
1654: static void *tls_cleanup_run(void *data)
1655: {
1656: int i;
1657:
1658: for (i = 0; i < countof(tls); i++)
1659: {
1660: tls[i]->set(tls[i], data);
1661: }
1662: return NULL;
1663: }
1664:
1665: START_TEST(test_tls_cleanup)
1666: {
1667: thread_t *threads[THREADS];
1668: uintptr_t values[THREADS], main_value = countof(tls);
1669: int i;
1670:
1671: for (i = 0; i < countof(tls); i++)
1672: {
1673: tls[i] = thread_value_create(tls_cleanup);
1674: }
1675: for (i = 0; i < THREADS; i++)
1676: {
1677: values[i] = countof(tls);
1678: threads[i] = thread_create(tls_cleanup_run, &values[i]);
1679: }
1680:
1681: tls_cleanup_run(&main_value);
1682:
1683: for (i = 0; i < THREADS; i++)
1684: {
1685: threads[i]->join(threads[i]);
1686: ck_assert_int_eq(values[i], 0);
1687: }
1688: for (i = 0; i < countof(tls); i++)
1689: {
1690: tls[i]->destroy(tls[i]);
1691: }
1692: ck_assert_int_eq(main_value, 0);
1693: }
1694: END_TEST
1695:
1696: Suite *threading_suite_create()
1697: {
1698: Suite *s;
1699: TCase *tc;
1700:
1701: s = suite_create("threading");
1702:
1703: tc = tcase_create("recursive mutex");
1704: tcase_add_test(tc, test_mutex);
1705: suite_add_tcase(s, tc);
1706:
1707: tc = tcase_create("spinlock");
1708: tcase_add_test(tc, test_spinlock);
1709: suite_add_tcase(s, tc);
1710:
1711: tc = tcase_create("condvar");
1712: tcase_add_test(tc, test_condvar);
1713: tcase_add_test(tc, test_condvar_recursive);
1714: tcase_add_test(tc, test_condvar_broad);
1715: tcase_add_test(tc, test_condvar_timed);
1716: tcase_add_test(tc, test_condvar_timed_abs);
1717: tcase_add_test(tc, test_condvar_cancel);
1718: suite_add_tcase(s, tc);
1719:
1720: tc = tcase_create("rwlock");
1721: tcase_add_test(tc, test_rwlock);
1722: tcase_add_test(tc, test_rwlock_try);
1723: suite_add_tcase(s, tc);
1724:
1725: tc = tcase_create("rwlock condvar");
1726: tcase_add_test(tc, test_rwlock_condvar);
1727: tcase_add_test(tc, test_rwlock_condvar_broad);
1728: tcase_add_test(tc, test_rwlock_condvar_timed);
1729: tcase_add_test(tc, test_rwlock_condvar_timed_abs);
1730: tcase_add_test(tc, test_rwlock_condvar_cancel);
1731: suite_add_tcase(s, tc);
1732:
1733: tc = tcase_create("semaphore");
1734: tcase_add_test(tc, test_semaphore);
1735: tcase_add_test(tc, test_semaphore_timed);
1736: tcase_add_test(tc, test_semaphore_timed_abs);
1737: tcase_add_test(tc, test_semaphore_cancel);
1738: suite_add_tcase(s, tc);
1739:
1740: tc = tcase_create("thread joining");
1741: tcase_add_test(tc, test_join);
1742: tcase_add_test(tc, test_join_exit);
1743: suite_add_tcase(s, tc);
1744:
1745: tc = tcase_create("thread detaching");
1746: tcase_add_test(tc, test_detach);
1747: tcase_add_test(tc, test_detach_exit);
1748: suite_add_tcase(s, tc);
1749:
1750: tc = tcase_create("thread cancellation");
1751: tcase_add_test(tc, test_cancel);
1752: tcase_add_test(tc, test_cancel_onoff);
1753: tcase_add_test(tc, test_cancel_point);
1754: suite_add_tcase(s, tc);
1755:
1756: tc = tcase_create("thread cancellation point");
1757: tcase_add_loop_test(tc, test_cancellation_point,
1758: 0, countof(cancellation_points));
1759: tcase_add_loop_test(tc, test_cancellation_point_pre,
1760: 0, countof(cancellation_points));
1761: suite_add_tcase(s, tc);
1762:
1763: tc = tcase_create("thread cleanup");
1764: tcase_add_test(tc, test_cleanup);
1765: tcase_add_test(tc, test_cleanup_exit);
1766: tcase_add_test(tc, test_cleanup_cancel);
1767: tcase_add_test(tc, test_cleanup_pop);
1768: tcase_add_test(tc, test_cleanup_popall);
1769: suite_add_tcase(s, tc);
1770:
1771: tc = tcase_create("thread local storage");
1772: tcase_add_test(tc, test_tls);
1773: tcase_add_test(tc, test_tls_cleanup);
1774: suite_add_tcase(s, tc);
1775:
1776: return s;
1777: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>