Return to test_threading.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / libstrongswan / tests / suites |
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: 1121: static void *cancel_onoff_run(void *data) 1122: { 1123: bool *cancellable = (bool*)data; 1124: 1125: thread_cancelability(FALSE); 1126: *cancellable = FALSE; 1127: 1128: /* we should not get cancelled here */ 1129: usleep(50000); 1130: 1131: *cancellable = TRUE; 1132: thread_cancelability(TRUE); 1133: 1134: /* but here */ 1135: while (TRUE) 1136: { 1137: sleep(10); 1138: } 1139: return NULL; 1140: } 1141: 1142: START_TEST(test_cancel_onoff) 1143: { 1144: thread_t *threads[THREADS]; 1145: bool cancellable[THREADS]; 1146: int i; 1147: 1148: for (i = 0; i < THREADS; i++) 1149: { 1150: cancellable[i] = TRUE; 1151: threads[i] = thread_create(cancel_onoff_run, &cancellable[i]); 1152: } 1153: for (i = 0; i < THREADS; i++) 1154: { 1155: /* wait until thread has cleared its cancelability */ 1156: while (cancellable[i]) 1157: { 1158: sched_yield(); 1159: } 1160: threads[i]->cancel(threads[i]); 1161: } 1162: for (i = 0; i < THREADS; i++) 1163: { 1164: threads[i]->join(threads[i]); 1165: ck_assert(cancellable[i]); 1166: } 1167: } 1168: END_TEST 1169: 1170: static void *cancel_point_run(void *data) 1171: { 1172: thread_cancelability(FALSE); 1173: while (TRUE) 1174: { 1175: /* implicitly enables cancelability */ 1176: thread_cancellation_point(); 1177: } 1178: return NULL; 1179: } 1180: 1181: START_TEST(test_cancel_point) 1182: { 1183: thread_t *threads[THREADS]; 1184: int i; 1185: 1186: for (i = 0; i < THREADS; i++) 1187: { 1188: threads[i] = thread_create(cancel_point_run, NULL); 1189: } 1190: sched_yield(); 1191: for (i = 0; i < THREADS; i++) 1192: { 1193: threads[i]->cancel(threads[i]); 1194: } 1195: for (i = 0; i < THREADS; i++) 1196: { 1197: threads[i]->join(threads[i]); 1198: } 1199: } 1200: END_TEST 1201: 1202: static void close_fd_ptr(void *fd) 1203: { 1204: close(*(int*)fd); 1205: } 1206: 1207: static void cancellation_recv() 1208: { 1209: int sv[2]; 1210: char buf[1]; 1211: 1212: ck_assert(socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == 0); 1213: 1214: thread_cleanup_push(close_fd_ptr, &sv[0]); 1215: thread_cleanup_push(close_fd_ptr, &sv[1]); 1216: 1217: thread_cancelability(TRUE); 1218: while (TRUE) 1219: { 1220: ck_assert(recv(sv[0], buf, sizeof(buf), 0) == 1); 1221: } 1222: } 1223: 1224: static void cancellation_read() 1225: { 1226: int sv[2]; 1227: char buf[1]; 1228: 1229: ck_assert(socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == 0); 1230: 1231: thread_cleanup_push(close_fd_ptr, &sv[0]); 1232: thread_cleanup_push(close_fd_ptr, &sv[1]); 1233: 1234: thread_cancelability(TRUE); 1235: while (TRUE) 1236: { 1237: ck_assert(read(sv[0], buf, sizeof(buf)) == 1); 1238: } 1239: } 1240: 1241: static void cancellation_select() 1242: { 1243: int sv[2]; 1244: fd_set set; 1245: 1246: ck_assert(socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == 0); 1247: 1248: thread_cleanup_push(close_fd_ptr, &sv[0]); 1249: thread_cleanup_push(close_fd_ptr, &sv[1]); 1250: 1251: FD_ZERO(&set); 1252: FD_SET(sv[0], &set); 1253: thread_cancelability(TRUE); 1254: while (TRUE) 1255: { 1256: ck_assert(select(sv[0] + 1, &set, NULL, NULL, NULL) == 1); 1257: } 1258: } 1259: 1260: static void cancellation_poll() 1261: { 1262: int sv[2]; 1263: struct pollfd pfd; 1264: 1265: ck_assert(socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == 0); 1266: 1267: thread_cleanup_push(close_fd_ptr, &sv[0]); 1268: thread_cleanup_push(close_fd_ptr, &sv[1]); 1269: 1270: pfd.fd = sv[0]; 1271: pfd.events = POLLIN; 1272: thread_cancelability(TRUE); 1273: while (TRUE) 1274: { 1275: ck_assert(poll(&pfd, 1, -1) == 1); 1276: } 1277: } 1278: 1279: static void cancellation_accept() 1280: { 1281: host_t *host; 1282: int fd, c; 1283: 1284: fd = socket(AF_INET, SOCK_STREAM, 0); 1285: ck_assert(fd >= 0); 1286: host = host_create_from_string("127.0.0.1", 0); 1287: ck_assert_msg(bind(fd, host->get_sockaddr(host), 1288: *host->get_sockaddr_len(host)) == 0, "%m"); 1289: host->destroy(host); 1290: ck_assert(listen(fd, 5) == 0); 1291: 1292: thread_cleanup_push(close_fd_ptr, &fd); 1293: 1294: thread_cancelability(TRUE); 1295: while (TRUE) 1296: { 1297: c = accept(fd, NULL, NULL); 1298: ck_assert(c >= 0); 1299: close(c); 1300: } 1301: } 1302: 1303: static void cancellation_cond() 1304: { 1305: mutex_t *mutex; 1306: condvar_t *cond; 1307: 1308: mutex = mutex_create(MUTEX_TYPE_DEFAULT); 1309: cond = condvar_create(CONDVAR_TYPE_DEFAULT); 1310: mutex->lock(mutex); 1311: 1312: thread_cleanup_push((void*)mutex->destroy, mutex); 1313: thread_cleanup_push((void*)cond->destroy, cond); 1314: 1315: thread_cancelability(TRUE); 1316: while (TRUE) 1317: { 1318: cond->wait(cond, mutex); 1319: } 1320: } 1321: 1322: static void cancellation_rwcond() 1323: { 1324: rwlock_t *lock; 1325: rwlock_condvar_t *cond; 1326: 1327: lock = rwlock_create(RWLOCK_TYPE_DEFAULT); 1328: cond = rwlock_condvar_create(); 1329: lock->write_lock(lock); 1330: 1331: thread_cleanup_push((void*)lock->destroy, lock); 1332: thread_cleanup_push((void*)cond->destroy, cond); 1333: 1334: thread_cancelability(TRUE); 1335: while (TRUE) 1336: { 1337: cond->wait(cond, lock); 1338: } 1339: } 1340: 1341: static void (*cancellation_points[])() = { 1342: cancellation_read, 1343: cancellation_recv, 1344: cancellation_select, 1345: cancellation_poll, 1346: cancellation_accept, 1347: cancellation_cond, 1348: cancellation_rwcond, 1349: }; 1350: 1351: static void* run_cancellation_point(void (*fn)()) 1352: { 1353: fn(); 1354: return NULL; 1355: } 1356: 1357: static void* run_cancellation_point_pre(void (*fn)()) 1358: { 1359: usleep(5000); 1360: fn(); 1361: return NULL; 1362: } 1363: 1364: START_TEST(test_cancellation_point) 1365: { 1366: thread_t *thread; 1367: 1368: thread = thread_create((void*)run_cancellation_point, 1369: cancellation_points[_i]); 1370: usleep(5000); 1371: thread->cancel(thread); 1372: thread->join(thread); 1373: } 1374: END_TEST 1375: 1376: START_TEST(test_cancellation_point_pre) 1377: { 1378: thread_t *thread; 1379: 1380: thread = thread_create((void*)run_cancellation_point_pre, 1381: cancellation_points[_i]); 1382: thread->cancel(thread); 1383: thread->join(thread); 1384: } 1385: END_TEST 1386: 1387: static void cleanup1(void *data) 1388: { 1389: uintptr_t *value = (uintptr_t*)data; 1390: 1391: ck_assert_int_eq(*value, 1); 1392: (*value)++; 1393: } 1394: 1395: static void cleanup2(void *data) 1396: { 1397: uintptr_t *value = (uintptr_t*)data; 1398: 1399: ck_assert_int_eq(*value, 2); 1400: (*value)++; 1401: } 1402: 1403: static void cleanup3(void *data) 1404: { 1405: uintptr_t *value = (uintptr_t*)data; 1406: 1407: ck_assert_int_eq(*value, 3); 1408: (*value)++; 1409: } 1410: 1411: static void *cleanup_run(void *data) 1412: { 1413: thread_cleanup_push(cleanup3, data); 1414: thread_cleanup_push(cleanup2, data); 1415: thread_cleanup_push(cleanup1, data); 1416: return NULL; 1417: } 1418: 1419: START_TEST(test_cleanup) 1420: { 1421: thread_t *threads[THREADS]; 1422: uintptr_t values[THREADS]; 1423: int i; 1424: 1425: for (i = 0; i < THREADS; i++) 1426: { 1427: values[i] = 1; 1428: threads[i] = thread_create(cleanup_run, &values[i]); 1429: } 1430: for (i = 0; i < THREADS; i++) 1431: { 1432: threads[i]->join(threads[i]); 1433: ck_assert_int_eq(values[i], 4); 1434: } 1435: } 1436: END_TEST 1437: 1438: static void *cleanup_exit_run(void *data) 1439: { 1440: thread_cleanup_push(cleanup3, data); 1441: thread_cleanup_push(cleanup2, data); 1442: thread_cleanup_push(cleanup1, data); 1443: thread_exit(NULL); 1444: ck_assert(FALSE); 1445: return NULL; 1446: } 1447: 1448: START_TEST(test_cleanup_exit) 1449: { 1450: thread_t *threads[THREADS]; 1451: uintptr_t values[THREADS]; 1452: int i; 1453: 1454: for (i = 0; i < THREADS; i++) 1455: { 1456: values[i] = 1; 1457: threads[i] = thread_create(cleanup_exit_run, &values[i]); 1458: } 1459: for (i = 0; i < THREADS; i++) 1460: { 1461: threads[i]->join(threads[i]); 1462: ck_assert_int_eq(values[i], 4); 1463: } 1464: } 1465: END_TEST 1466: 1467: static void *cleanup_cancel_run(void *data) 1468: { 1469: thread_cancelability(FALSE); 1470: 1471: barrier_wait(barrier); 1472: 1473: thread_cleanup_push(cleanup3, data); 1474: thread_cleanup_push(cleanup2, data); 1475: thread_cleanup_push(cleanup1, data); 1476: 1477: thread_cancelability(TRUE); 1478: 1479: while (TRUE) 1480: { 1481: sleep(1); 1482: } 1483: return NULL; 1484: } 1485: 1486: START_TEST(test_cleanup_cancel) 1487: { 1488: thread_t *threads[THREADS]; 1489: uintptr_t values[THREADS]; 1490: int i; 1491: 1492: barrier = barrier_create(THREADS+1); 1493: for (i = 0; i < THREADS; i++) 1494: { 1495: values[i] = 1; 1496: threads[i] = thread_create(cleanup_cancel_run, &values[i]); 1497: } 1498: barrier_wait(barrier); 1499: for (i = 0; i < THREADS; i++) 1500: { 1501: threads[i]->cancel(threads[i]); 1502: } 1503: for (i = 0; i < THREADS; i++) 1504: { 1505: threads[i]->join(threads[i]); 1506: ck_assert_int_eq(values[i], 4); 1507: } 1508: barrier_destroy(barrier); 1509: } 1510: END_TEST 1511: 1512: static void *cleanup_pop_run(void *data) 1513: { 1514: thread_cleanup_push(cleanup3, data); 1515: thread_cleanup_push(cleanup2, data); 1516: thread_cleanup_push(cleanup1, data); 1517: 1518: thread_cleanup_push(cleanup2, data); 1519: thread_cleanup_pop(FALSE); 1520: 1521: thread_cleanup_pop(TRUE); 1522: return NULL; 1523: } 1524: 1525: START_TEST(test_cleanup_pop) 1526: { 1527: thread_t *threads[THREADS]; 1528: uintptr_t values[THREADS]; 1529: int i; 1530: 1531: for (i = 0; i < THREADS; i++) 1532: { 1533: values[i] = 1; 1534: threads[i] = thread_create(cleanup_pop_run, &values[i]); 1535: } 1536: for (i = 0; i < THREADS; i++) 1537: { 1538: threads[i]->join(threads[i]); 1539: ck_assert_int_eq(values[i], 4); 1540: } 1541: } 1542: END_TEST 1543: 1544: static void *cleanup_popall_run(void *data) 1545: { 1546: thread_cleanup_push(cleanup3, data); 1547: thread_cleanup_push(cleanup2, data); 1548: thread_cleanup_push(cleanup1, data); 1549: 1550: thread_cleanup_popall(); 1551: return NULL; 1552: } 1553: 1554: START_TEST(test_cleanup_popall) 1555: { 1556: thread_t *threads[THREADS]; 1557: uintptr_t values[THREADS]; 1558: int i; 1559: 1560: for (i = 0; i < THREADS; i++) 1561: { 1562: values[i] = 1; 1563: threads[i] = thread_create(cleanup_popall_run, &values[i]); 1564: } 1565: for (i = 0; i < THREADS; i++) 1566: { 1567: threads[i]->join(threads[i]); 1568: ck_assert_int_eq(values[i], 4); 1569: } 1570: } 1571: END_TEST 1572: 1573: 1574: static thread_value_t *tls[10]; 1575: 1576: static void *tls_run(void *data) 1577: { 1578: uintptr_t value = (uintptr_t)data; 1579: int i, j; 1580: 1581: for (i = 0; i < countof(tls); i++) 1582: { 1583: ck_assert(tls[i]->get(tls[i]) == NULL); 1584: } 1585: for (i = 0; i < countof(tls); i++) 1586: { 1587: tls[i]->set(tls[i], (void*)(value * i)); 1588: } 1589: for (j = 0; j < 1000; j++) 1590: { 1591: for (i = 0; i < countof(tls); i++) 1592: { 1593: tls[i]->set(tls[i], (void*)(value * i)); 1594: ck_assert(tls[i]->get(tls[i]) == (void*)(value * i)); 1595: } 1596: sched_yield(); 1597: } 1598: for (i = 0; i < countof(tls); i++) 1599: { 1600: ck_assert(tls[i]->get(tls[i]) == (void*)(value * i)); 1601: } 1602: return (void*)(value + 1); 1603: } 1604: 1605: START_TEST(test_tls) 1606: { 1607: thread_t *threads[THREADS]; 1608: int i; 1609: 1610: for (i = 0; i < countof(tls); i++) 1611: { 1612: tls[i] = thread_value_create(NULL); 1613: } 1614: for (i = 0; i < THREADS; i++) 1615: { 1616: threads[i] = thread_create(tls_run, (void*)(uintptr_t)i); 1617: } 1618: 1619: ck_assert_int_eq((uintptr_t)tls_run((void*)(uintptr_t)(THREADS + 1)), 1620: THREADS + 2); 1621: 1622: for (i = 0; i < THREADS; i++) 1623: { 1624: ck_assert_int_eq((uintptr_t)threads[i]->join(threads[i]), i + 1); 1625: } 1626: for (i = 0; i < countof(tls); i++) 1627: { 1628: tls[i]->destroy(tls[i]); 1629: } 1630: } 1631: END_TEST 1632: 1633: static void tls_cleanup(void *data) 1634: { 1635: uintptr_t *value = (uintptr_t*)data; 1636: 1637: (*value)--; 1638: } 1639: 1640: static void *tls_cleanup_run(void *data) 1641: { 1642: int i; 1643: 1644: for (i = 0; i < countof(tls); i++) 1645: { 1646: tls[i]->set(tls[i], data); 1647: } 1648: return NULL; 1649: } 1650: 1651: START_TEST(test_tls_cleanup) 1652: { 1653: thread_t *threads[THREADS]; 1654: uintptr_t values[THREADS], main_value = countof(tls); 1655: int i; 1656: 1657: for (i = 0; i < countof(tls); i++) 1658: { 1659: tls[i] = thread_value_create(tls_cleanup); 1660: } 1661: for (i = 0; i < THREADS; i++) 1662: { 1663: values[i] = countof(tls); 1664: threads[i] = thread_create(tls_cleanup_run, &values[i]); 1665: } 1666: 1667: tls_cleanup_run(&main_value); 1668: 1669: for (i = 0; i < THREADS; i++) 1670: { 1671: threads[i]->join(threads[i]); 1672: ck_assert_int_eq(values[i], 0); 1673: } 1674: for (i = 0; i < countof(tls); i++) 1675: { 1676: tls[i]->destroy(tls[i]); 1677: } 1678: ck_assert_int_eq(main_value, 0); 1679: } 1680: END_TEST 1681: 1682: Suite *threading_suite_create() 1683: { 1684: Suite *s; 1685: TCase *tc; 1686: 1687: s = suite_create("threading"); 1688: 1689: tc = tcase_create("recursive mutex"); 1690: tcase_add_test(tc, test_mutex); 1691: suite_add_tcase(s, tc); 1692: 1693: tc = tcase_create("spinlock"); 1694: tcase_add_test(tc, test_spinlock); 1695: suite_add_tcase(s, tc); 1696: 1697: tc = tcase_create("condvar"); 1698: tcase_add_test(tc, test_condvar); 1699: tcase_add_test(tc, test_condvar_recursive); 1700: tcase_add_test(tc, test_condvar_broad); 1701: tcase_add_test(tc, test_condvar_timed); 1702: tcase_add_test(tc, test_condvar_timed_abs); 1703: tcase_add_test(tc, test_condvar_cancel); 1704: suite_add_tcase(s, tc); 1705: 1706: tc = tcase_create("rwlock"); 1707: tcase_add_test(tc, test_rwlock); 1708: tcase_add_test(tc, test_rwlock_try); 1709: suite_add_tcase(s, tc); 1710: 1711: tc = tcase_create("rwlock condvar"); 1712: tcase_add_test(tc, test_rwlock_condvar); 1713: tcase_add_test(tc, test_rwlock_condvar_broad); 1714: tcase_add_test(tc, test_rwlock_condvar_timed); 1715: tcase_add_test(tc, test_rwlock_condvar_timed_abs); 1716: tcase_add_test(tc, test_rwlock_condvar_cancel); 1717: suite_add_tcase(s, tc); 1718: 1719: tc = tcase_create("semaphore"); 1720: tcase_add_test(tc, test_semaphore); 1721: tcase_add_test(tc, test_semaphore_timed); 1722: tcase_add_test(tc, test_semaphore_timed_abs); 1723: tcase_add_test(tc, test_semaphore_cancel); 1724: suite_add_tcase(s, tc); 1725: 1726: tc = tcase_create("thread joining"); 1727: tcase_add_test(tc, test_join); 1728: tcase_add_test(tc, test_join_exit); 1729: suite_add_tcase(s, tc); 1730: 1731: tc = tcase_create("thread detaching"); 1732: tcase_add_test(tc, test_detach); 1733: tcase_add_test(tc, test_detach_exit); 1734: suite_add_tcase(s, tc); 1735: 1736: tc = tcase_create("thread cancellation"); 1737: tcase_add_test(tc, test_cancel); 1738: tcase_add_test(tc, test_cancel_onoff); 1739: tcase_add_test(tc, test_cancel_point); 1740: suite_add_tcase(s, tc); 1741: 1742: tc = tcase_create("thread cancellation point"); 1743: tcase_add_loop_test(tc, test_cancellation_point, 1744: 0, countof(cancellation_points)); 1745: tcase_add_loop_test(tc, test_cancellation_point_pre, 1746: 0, countof(cancellation_points)); 1747: suite_add_tcase(s, tc); 1748: 1749: tc = tcase_create("thread cleanup"); 1750: tcase_add_test(tc, test_cleanup); 1751: tcase_add_test(tc, test_cleanup_exit); 1752: tcase_add_test(tc, test_cleanup_cancel); 1753: tcase_add_test(tc, test_cleanup_pop); 1754: tcase_add_test(tc, test_cleanup_popall); 1755: suite_add_tcase(s, tc); 1756: 1757: tc = tcase_create("thread local storage"); 1758: tcase_add_test(tc, test_tls); 1759: tcase_add_test(tc, test_tls_cleanup); 1760: suite_add_tcase(s, tc); 1761: 1762: return s; 1763: }