1 /* Test the mthreads library. When the library is compiled with -DMDEBUG, you 2 * have to compile this test with -DMDEBUG as well or it won't link. MDEBUG 3 * lets you check the internal integrity of the library. */ 4 #include <stdio.h> 5 #include <minix/mthread.h> 6 #include <signal.h> 7 8 #define thread_t mthread_thread_t 9 #define mutex_t mthread_mutex_t 10 #define cond_t mthread_cond_t 11 #define once_t mthread_once_t 12 #define attr_t mthread_attr_t 13 #define key_t mthread_key_t 14 #define event_t mthread_event_t 15 #define rwlock_t mthread_rwlock_t 16 17 int max_error = 5; 18 #include "common.h" 19 20 21 static int count, condition_met; 22 static int th_a, th_b, th_c, th_d, th_e, th_f, th_g, th_h; 23 static int mutex_a_step, mutex_b_step, mutex_c_step; 24 static mutex_t mu[3]; 25 static cond_t condition; 26 static mutex_t *count_mutex, *condition_mutex; 27 static once_t once; 28 static key_t key[MTHREAD_KEYS_MAX+1]; 29 static int values[4]; 30 static int first; 31 static event_t event; 32 static int event_a_step, event_b_step; 33 static rwlock_t rwlock; 34 static int rwlock_a_step, rwlock_b_step; 35 36 #define VERIFY_RWLOCK(a, b, esub, eno) \ 37 GEN_VERIFY(rwlock_a_step, a, rwlock_b_step, b, esub, eno) 38 39 #define VERIFY_EVENT(a, b, esub, eno) \ 40 GEN_VERIFY(event_a_step, a, event_b_step, b, esub, eno) 41 42 #define GEN_VERIFY(acta, a, actb, b, esub, eno) do { \ 43 if (acta != a) { \ 44 printf("Expected %d %d, got: %d %d\n", \ 45 a, b, acta, actb); \ 46 err(esub, eno); \ 47 } else if (actb != b) err(esub, eno); \ 48 } while(0) 49 50 #define VERIFY_MUTEX(a,b,c,esub,eno) do { \ 51 if (mutex_a_step != a) { \ 52 printf("Expected %d %d %d, got: %d %d %d\n", \ 53 a, b, c, mutex_a_step, mutex_b_step, mutex_c_step); \ 54 err(esub, eno); \ 55 } else if (mutex_b_step != b) err(esub, eno); \ 56 else if (mutex_c_step != c) err(esub, eno); \ 57 } while(0) 58 #define ROUNDS 14 59 #define THRESH1 3 60 #define THRESH2 8 61 #define MEG 1024*1024 62 #define MAGIC ((signed) 0xb4a3f1c2) 63 64 static void destr_a(void *arg); 65 static void destr_b(void *arg); 66 static void *thread_a(void *arg); 67 static void *thread_b(void *arg); 68 static void *thread_c(void *arg); 69 static void *thread_d(void *arg); 70 static void thread_e(void); 71 static void *thread_f(void *arg); 72 static void *thread_g(void *arg); 73 static void *thread_h(void *arg); 74 static void test_scheduling(void); 75 static void test_mutex(void); 76 static void test_condition(void); 77 static void test_attributes(void); 78 static void test_keys(void); 79 static void err(int subtest, int error); 80 81 /*===========================================================================* 82 * thread_a * 83 *===========================================================================*/ 84 static void *thread_a(void *arg) { 85 th_a++; 86 return(NULL); 87 } 88 89 90 /*===========================================================================* 91 * thread_b * 92 *===========================================================================*/ 93 static void *thread_b(void *arg) { 94 th_b++; 95 if (mthread_once(&once, thread_e) != 0) err(10, 1); 96 return(NULL); 97 } 98 99 100 /*===========================================================================* 101 * thread_c * 102 *===========================================================================*/ 103 static void *thread_c(void *arg) { 104 th_c++; 105 return(NULL); 106 } 107 108 109 /*===========================================================================* 110 * thread_d * 111 *===========================================================================*/ 112 static void *thread_d(void *arg) { 113 th_d++; 114 mthread_exit(NULL); /* Thread wants to stop running */ 115 return(NULL); 116 } 117 118 119 /*===========================================================================* 120 * thread_e * 121 *===========================================================================*/ 122 static void thread_e(void) { 123 th_e++; 124 } 125 126 127 /*===========================================================================* 128 * thread_f * 129 *===========================================================================*/ 130 static void *thread_f(void *arg) { 131 if (mthread_mutex_lock(condition_mutex) != 0) err(12, 1); 132 th_f++; 133 if (mthread_cond_signal(&condition) != 0) err(12, 2); 134 if (mthread_mutex_unlock(condition_mutex) != 0) err(12, 3); 135 return(NULL); 136 } 137 138 139 /*===========================================================================* 140 * thread_g * 141 *===========================================================================*/ 142 static void *thread_g(void *arg) { 143 char bigarray[MTHREAD_STACK_MIN + 1]; 144 if (mthread_mutex_lock(condition_mutex) != 0) err(13, 1); 145 memset(bigarray, '\0', MTHREAD_STACK_MIN + 1); /* Actually allocate it */ 146 th_g++; 147 if (mthread_cond_signal(&condition) != 0) err(13, 2); 148 if (mthread_mutex_unlock(condition_mutex) != 0) err(13, 3); 149 return(NULL); 150 } 151 152 153 /*===========================================================================* 154 * thread_h * 155 *===========================================================================*/ 156 static void *thread_h(void *arg) { 157 char bigarray[2 * MEG]; 158 int reply; 159 if (mthread_mutex_lock(condition_mutex) != 0) err(14, 1); 160 memset(bigarray, '\0', 2 * MEG); /* Actually allocate it */ 161 th_h++; 162 if (mthread_cond_signal(&condition) != 0) err(14, 2); 163 if (mthread_mutex_unlock(condition_mutex) != 0) err(14, 3); 164 reply = *((int *) arg); 165 mthread_exit((void *) reply); 166 return(NULL); 167 } 168 169 170 /*===========================================================================* 171 * err * 172 *===========================================================================*/ 173 static void err(int sub, int error) { 174 /* As we're running with multiple threads, they might all clobber the 175 * subtest variable. This wrapper prevents that from happening. */ 176 177 subtest = sub; 178 e(error); 179 } 180 181 182 /*===========================================================================* 183 * test_scheduling * 184 *===========================================================================*/ 185 static void test_scheduling(void) 186 { 187 unsigned int i; 188 thread_t t[7]; 189 190 #ifdef MDEBUG 191 mthread_verify(); 192 #endif 193 th_a = th_b = th_c = th_d = th_e = 0; 194 195 if (mthread_create(&t[0], NULL, thread_a, NULL) != 0) err(1, 1); 196 if (mthread_create(&t[1], NULL, thread_a, NULL) != 0) err(1, 2); 197 if (mthread_create(&t[2], NULL, thread_a, NULL) != 0) err(1, 3); 198 if (mthread_create(&t[3], NULL, thread_d, NULL) != 0) err(1, 4); 199 if (mthread_once(&once, thread_e) != 0) err(1, 5); 200 201 mthread_yield(); 202 203 if (mthread_create(&t[4], NULL, thread_c, NULL) != 0) err(1, 6); 204 mthread_yield(); 205 if (mthread_create(&t[5], NULL, thread_b, NULL) != 0) err(1, 7); 206 if (mthread_create(&t[6], NULL, thread_a, NULL) != 0) err(1, 8); 207 mthread_yield(); 208 mthread_yield(); 209 if (mthread_once(&once, thread_e) != 0) err(1, 9); 210 if (mthread_once(&once, thread_e) != 0) err(1, 10); 211 212 if (th_a != 4) err(1, 11); 213 if (th_b != 1) err(1, 12); 214 if (th_c != 1) err(1, 13); 215 if (th_d != 1) err(1, 14); 216 if (th_e != 1) err(1, 15); 217 218 for (i = 0; i < (sizeof(t) / sizeof(thread_t)); i++) { 219 if (mthread_join(t[i], NULL) != 0) err(1, 16); 220 if (mthread_join(t[i], NULL) == 0) err(1, 17); /*Shouldn't work twice*/ 221 } 222 223 #ifdef MDEBUG 224 mthread_verify(); 225 #endif 226 if (mthread_create(NULL, NULL, NULL, NULL) == 0) err(1, 18); 227 mthread_yield(); 228 229 #ifdef MDEBUG 230 mthread_verify(); 231 #endif 232 if (mthread_create(&t[6], NULL, NULL, NULL) == 0) err(1, 19); 233 mthread_yield(); 234 #ifdef MDEBUG 235 mthread_verify(); 236 #endif 237 if (mthread_join(0xc0ffee, NULL) == 0) err(1, 20); 238 mthread_yield(); 239 mthread_yield(); 240 241 #ifdef MDEBUG 242 mthread_verify(); 243 #endif 244 } 245 246 247 /*===========================================================================* 248 * mutex_a * 249 *===========================================================================*/ 250 static void *mutex_a(void *arg) 251 { 252 mutex_t *mu = (mutex_t *) arg; 253 254 VERIFY_MUTEX(0, 0, 0, 3, 1); 255 if (mthread_mutex_lock(&mu[0]) != 0) err(3, 2); 256 257 /* Trying to acquire lock again should fail with EDEADLK */ 258 if (mthread_mutex_lock(&mu[0]) != EDEADLK) err(3, 2); 259 260 #ifdef MTHREAD_STRICT 261 /* Try to acquire lock on uninitialized mutex; should fail with EINVAL */ 262 /* Note: this check only works when libmthread is compiled with 263 * MTHREAD_STRICT turned on. In POSIX this situation is a MAY fail if... */ 264 if (mthread_mutex_lock(&mu2) != EINVAL) { 265 err(3, 4); 266 mthread_mutex_unlock(&mu2); 267 } 268 269 if (mthread_mutex_trylock(&mu2) != EINVAL) { 270 err(3, 6); 271 mthread_mutex_unlock(&mu2); 272 } 273 #endif 274 275 if (mthread_mutex_trylock(&mu[1]) != 0) err(3, 8); 276 mutex_a_step = 1; 277 mthread_yield(); 278 VERIFY_MUTEX(1, 0, 0, 3, 9); 279 if (mthread_mutex_trylock(&mu[2]) != EBUSY) err(3, 10); 280 if (mthread_mutex_lock(&mu[2]) != 0) err(3, 12); /* Transfer control to main 281 * loop. 282 */ 283 VERIFY_MUTEX(1, 0, 0, 3, 13); 284 285 if (mthread_mutex_unlock(&mu[0]) != 0) err(3, 14); 286 mutex_a_step = 2; 287 mthread_yield(); 288 289 VERIFY_MUTEX(2, 1, 0, 3, 15); 290 if (mthread_mutex_unlock(&mu[1]) != 0) err(3, 16); 291 mutex_a_step = 3; 292 293 /* Try with faulty memory locations */ 294 if (mthread_mutex_lock(NULL) == 0) err(3, 17); 295 if (mthread_mutex_trylock(NULL) == 0) err(3, 18); 296 if (mthread_mutex_unlock(NULL) == 0) err(3, 19); 297 298 if (mthread_mutex_unlock(&mu[2]) != 0) err(3, 20); 299 return(NULL); 300 } 301 302 303 /*===========================================================================* 304 * mutex_b * 305 *===========================================================================*/ 306 static void *mutex_b(void *arg) 307 { 308 mutex_t *mu = (mutex_t *) arg; 309 310 /* At this point mutex_a thread should have acquired a lock on mu[0]. We 311 * should not be able to unlock it on behalf of that thread. 312 */ 313 314 VERIFY_MUTEX(1, 0, 0, 4, 1); 315 if (mthread_mutex_unlock(&mu[0]) != EPERM) err(4, 2); 316 317 /* Probing mu[0] to lock it should tell us it's locked */ 318 if (mthread_mutex_trylock(&mu[0]) != EBUSY) err(4, 4); 319 320 if (mthread_mutex_lock(&mu[0]) != 0) err(4, 5); 321 mutex_b_step = 1; 322 VERIFY_MUTEX(2, 1, 0, 4, 6); 323 if (mthread_mutex_lock(&mu[1]) != 0) err(4, 6); 324 mutex_b_step = 2; 325 VERIFY_MUTEX(3, 2, 2, 4, 7); 326 mthread_yield(); 327 VERIFY_MUTEX(3, 2, 2, 4, 8); 328 329 if (mthread_mutex_unlock(&mu[0]) != 0) err(4, 7); 330 mutex_b_step = 3; 331 mthread_yield(); 332 333 if (mthread_mutex_unlock(&mu[1]) != 0) err(4, 8); 334 mutex_b_step = 4; 335 return(NULL); 336 } 337 338 339 /*===========================================================================* 340 * mutex_c * 341 *===========================================================================*/ 342 static void *mutex_c(void *arg) 343 { 344 mutex_t *mu = (mutex_t *) arg; 345 346 VERIFY_MUTEX(1, 0, 0, 5, 1); 347 if (mthread_mutex_lock(&mu[1]) != 0) err(5, 2); 348 mutex_c_step = 1; 349 VERIFY_MUTEX(3, 1, 1, 5, 3); 350 mthread_yield(); 351 VERIFY_MUTEX(3, 1, 1, 5, 4); 352 353 if (mthread_mutex_unlock(&mu[1]) != 0) err(5, 5); 354 mutex_c_step = 2; 355 if (mthread_mutex_lock(&mu[0]) != 0) err(5, 6); 356 mutex_c_step = 3; 357 VERIFY_MUTEX(3, 3, 3, 5, 7); 358 mthread_yield(); 359 VERIFY_MUTEX(3, 4, 3, 5, 8); 360 361 if (mthread_mutex_unlock(&mu[0]) != 0) err(5, 9); 362 mutex_c_step = 4; 363 return(NULL); 364 } 365 366 367 /*===========================================================================* 368 * test_mutex * 369 *===========================================================================*/ 370 static void test_mutex(void) 371 { 372 unsigned int i; 373 thread_t t[3]; 374 #ifdef MDEBUG 375 mthread_verify(); 376 #endif 377 if (mthread_mutex_init(&mu[0], NULL) != 0) err(2, 1); 378 if (mthread_mutex_init(&mu[1], NULL) != 0) err(2, 2); 379 if (mthread_mutex_init(&mu[2], NULL) != 0) err(2, 3); 380 381 if (mthread_create(&t[0], NULL, mutex_a, (void *) mu) != 0) err(2, 3); 382 if (mthread_create(&t[1], NULL, mutex_b, (void *) mu) != 0) err(2, 4); 383 if (mthread_create(&t[2], NULL, mutex_c, (void *) mu) != 0) err(2, 5); 384 385 if (mthread_mutex_lock(&mu[2]) != 0) err(2, 6); 386 387 mthread_yield_all(); /* Should result in a RUNNABLE mutex_a, and a blocked 388 * on mutex mutex_b and mutex_c. 389 */ 390 391 VERIFY_MUTEX(1, 0, 0, 2, 7); /* err(2, 7) */ 392 if (mthread_mutex_unlock(&mu[2]) != 0) err(2, 8); 393 394 mthread_yield(); /* Should schedule mutex_a to release the lock on the 395 * mu[0] mutex. Consequently allowing mutex_b and mutex_c 396 * to acquire locks on the mutexes and exit. 397 */ 398 VERIFY_MUTEX(2, 0, 0, 2, 9); 399 400 for (i = 0; i < (sizeof(t) / sizeof(thread_t)); i++) 401 if (mthread_join(t[i], NULL) != 0) err(2, 10); 402 403 if (mthread_mutex_destroy(&mu[0]) != 0) err(2, 11); 404 if (mthread_mutex_destroy(&mu[1]) != 0) err(2, 12); 405 if (mthread_mutex_destroy(&mu[2]) != 0) err(2, 13); 406 407 #ifdef MDEBUG 408 mthread_verify(); 409 #endif 410 } 411 412 413 /*===========================================================================* 414 * cond_a * 415 *===========================================================================*/ 416 static void *cond_a(void *arg) 417 { 418 cond_t c; 419 int did_count = 0; 420 while(1) { 421 if (mthread_mutex_lock(condition_mutex) != 0) err(6, 1); 422 while (count >= THRESH1 && count <= THRESH2) { 423 if (mthread_cond_wait(&condition, condition_mutex) != 0) 424 err(6, 2); 425 } 426 if (mthread_mutex_unlock(condition_mutex) != 0) err(6, 3); 427 428 mthread_yield(); 429 430 if (mthread_mutex_lock(count_mutex) != 0) err(6, 4); 431 count++; 432 did_count++; 433 if (mthread_mutex_unlock(count_mutex) != 0) err(6, 5); 434 435 if (count >= ROUNDS) break; 436 } 437 if (!(did_count <= count - (THRESH2 - THRESH1 + 1))) err(6, 6); 438 439 /* Try faulty addresses */ 440 if (mthread_mutex_lock(condition_mutex) != 0) err(6, 7); 441 #ifdef MTHREAD_STRICT 442 /* Condition c is not initialized, so whatever we do with it should fail. */ 443 if (mthread_cond_wait(&c, condition_mutex) == 0) err(6, 8); 444 if (mthread_cond_wait(NULL, condition_mutex) == 0) err(6, 9); 445 if (mthread_cond_signal(&c) == 0) err(6, 10); 446 if (mthread_mutex_unlock(condition_mutex) != 0) err(6, 11); 447 448 /* Try again with an unlocked mutex */ 449 if (mthread_cond_wait(&c, condition_mutex) == 0) err(6, 12); 450 if (mthread_cond_signal(&c) == 0) err(6, 13); 451 #endif 452 453 /* And again with an unlocked mutex, but initialized c */ 454 if (mthread_cond_init(&c, NULL) != 0) err(6, 14); 455 if (mthread_cond_wait(&c, condition_mutex) == 0) err(6, 15); 456 if (mthread_cond_signal(&c) != 0) err(6, 16);/*c.f., 6.10 this should work!*/ 457 if (mthread_cond_destroy(&c) != 0) err(6, 17); 458 return(NULL); 459 } 460 461 462 /*===========================================================================* 463 * cond_b * 464 *===========================================================================*/ 465 static void *cond_b(void *arg) 466 { 467 int did_count = 0; 468 while(1) { 469 if (mthread_mutex_lock(condition_mutex) != 0) err(7, 1); 470 if (count < THRESH1 || count > THRESH2) 471 if (mthread_cond_signal(&condition) != 0) err(7, 2); 472 if (mthread_mutex_unlock(condition_mutex) != 0) err(7, 3); 473 474 mthread_yield(); 475 476 if (mthread_mutex_lock(count_mutex) != 0) err(7, 4); 477 count++; 478 did_count++; 479 if (mthread_mutex_unlock(count_mutex) != 0) err(7, 5); 480 481 if (count >= ROUNDS) break; 482 } 483 484 if (!(did_count >= count - (THRESH2 - THRESH1 + 1))) err(7, 6); 485 486 return(NULL); 487 } 488 489 /*===========================================================================* 490 * cond_broadcast * 491 *===========================================================================*/ 492 static void *cond_broadcast(void *arg) 493 { 494 if (mthread_mutex_lock(condition_mutex) != 0) err(9, 1); 495 496 while(!condition_met) 497 if (mthread_cond_wait(&condition, condition_mutex) != 0) err(9, 2); 498 499 if (mthread_mutex_unlock(condition_mutex) != 0) err(9, 3); 500 501 if (mthread_mutex_lock(count_mutex) != 0) err(9, 4); 502 count++; 503 if (mthread_mutex_unlock(count_mutex) != 0) err(9, 5); 504 return(NULL); 505 } 506 507 /*===========================================================================* 508 * test_condition * 509 *===========================================================================*/ 510 static void test_condition(void) 511 { 512 #define NTHREADS 10 513 int i; 514 thread_t t[2], s[NTHREADS]; 515 count_mutex = &mu[0]; 516 condition_mutex = &mu[1]; 517 518 /* Test simple condition variable behavior: Two threads increase a counter. 519 * At some point one thread waits for a condition and the other thread 520 * signals the condition. Consequently, one thread increased the counter a 521 * few times less than other thread. Although the difference is 'random', 522 * there is a guaranteed minimum difference that we can measure. 523 */ 524 525 #ifdef MDEBUG 526 mthread_verify(); 527 #endif 528 529 if (mthread_mutex_init(count_mutex, NULL) != 0) err(8, 1); 530 if (mthread_mutex_init(condition_mutex, NULL) != 0) err(8, 2); 531 if (mthread_cond_init(&condition, NULL) != 0) err(8, 3); 532 count = 0; 533 534 if (mthread_create(&t[0], NULL, cond_a, NULL) != 0) err(8, 4); 535 if (mthread_create(&t[1], NULL, cond_b, NULL) != 0) err(8, 5); 536 537 for (i = 0; i < (sizeof(t) / sizeof(thread_t)); i++) 538 if (mthread_join(t[i], NULL) != 0) err(8, 6); 539 540 if (mthread_mutex_destroy(count_mutex) != 0) err(8, 7); 541 if (mthread_mutex_destroy(condition_mutex) != 0) err(8, 8); 542 if (mthread_cond_destroy(&condition) != 0) err(8, 9); 543 544 #ifdef MTHREAD_STRICT 545 /* Let's try to destroy it again. Should fails as it's uninitialized. */ 546 /* Note: this only works when libmthread is compiled with MTHREAD_STRICT. In 547 * POSIX this situation is a MAY fail if... */ 548 if (mthread_cond_destroy(&condition) == 0) err(8, 10); 549 #endif 550 551 #ifdef MDEBUG 552 mthread_verify(); 553 #endif 554 555 /* Test signal broadcasting: spawn N threads that will increase a counter 556 * after a condition has been signaled. The counter must equal N. */ 557 if (mthread_mutex_init(count_mutex, NULL) != 0) err(8, 11); 558 if (mthread_mutex_init(condition_mutex, NULL) != 0) err(8, 12); 559 if (mthread_cond_init(&condition, NULL) != 0) err(8, 13); 560 condition_met = count = 0; 561 562 for (i = 0; i < NTHREADS; i++) 563 if (mthread_create(&s[i], NULL, cond_broadcast, NULL) != 0) err(8, 14); 564 565 /* Allow other threads to block on the condition variable. If we don't yield, 566 * the threads will only start running when we call mthread_join below. In 567 * that case the while loop in cond_broadcast will never evaluate to true. 568 */ 569 mthread_yield(); 570 571 if (mthread_mutex_lock(condition_mutex) != 0) err(8, 15); 572 condition_met = 1; 573 if (mthread_cond_broadcast(&condition) != 0) err(8, 16); 574 if (mthread_mutex_unlock(condition_mutex) != 0) err(8, 17); 575 576 for (i = 0; i < (sizeof(s) / sizeof(thread_t)); i++) 577 if (mthread_join(s[i], NULL) != 0) err(8, 18); 578 579 if (count != NTHREADS) err(8, 19); 580 if (mthread_mutex_destroy(count_mutex) != 0) err(8, 20); 581 if (mthread_mutex_destroy(condition_mutex) != 0) err(8, 21); 582 if (mthread_cond_destroy(&condition) != 0) err(8, 22); 583 584 #ifdef MTHREAD_STRICT 585 /* Again, destroying the condition variable twice shouldn't work */ 586 /* See previous note about MTHREAD_STRICT */ 587 if (mthread_cond_destroy(&condition) == 0) err(8, 23); 588 #endif 589 590 #ifdef MDEBUG 591 mthread_verify(); 592 #endif 593 } 594 595 /*===========================================================================* 596 * test_attributes * 597 *===========================================================================*/ 598 static void test_attributes(void) 599 { 600 attr_t tattr; 601 thread_t tid; 602 int detachstate = -1; 603 unsigned int i, no_ints, stack_untouched = 1; 604 void *status, *stackaddr, *newstackaddr; 605 int *stackp; 606 size_t stacksize, newstacksize; 607 608 #ifdef MDEBUG 609 mthread_verify(); 610 #endif 611 612 /* Initialize thread attribute and try to read the default values */ 613 if (mthread_attr_init(&tattr) != 0) err(11, 1); 614 if (mthread_attr_getdetachstate(&tattr, &detachstate) != 0) err(11, 2); 615 if (detachstate != MTHREAD_CREATE_JOINABLE) err(11, 3); 616 if (mthread_attr_getstack(&tattr, &stackaddr, &stacksize) != 0) err(11, 4); 617 if (stackaddr != NULL) err(11, 5); 618 if (stacksize != (size_t) 0) err(11, 6); 619 620 /* Modify the attribute ... */ 621 /* Try bogus detach state value */ 622 if (mthread_attr_setdetachstate(&tattr, 0xc0ffee) == 0) err(11, 7); 623 if (mthread_attr_setdetachstate(&tattr, MTHREAD_CREATE_DETACHED) != 0) 624 err(11, 8); 625 newstacksize = (size_t) MEG; 626 if ((newstackaddr = malloc(newstacksize)) == NULL) err(11, 9); 627 if (mthread_attr_setstack(&tattr, newstackaddr, newstacksize) != 0) 628 err(11, 10); 629 /* ... and read back the new values. */ 630 if (mthread_attr_getdetachstate(&tattr, &detachstate) != 0) err(11, 11); 631 if (detachstate != MTHREAD_CREATE_DETACHED) err(11, 12); 632 if (mthread_attr_getstack(&tattr, &stackaddr, &stacksize) != 0) err(11, 13); 633 if (stackaddr != newstackaddr) err(11, 14); 634 if (stacksize != newstacksize) err(11, 15); 635 if (mthread_attr_destroy(&tattr) != 0) err(11, 16); 636 free(newstackaddr); 637 638 /* Try to allocate too small a stack; it should fail and the attribute 639 * values should remain as is. 640 */ 641 newstacksize = MTHREAD_STACK_MIN - 1; 642 stackaddr = NULL; 643 stacksize = 0; 644 if (mthread_attr_init(&tattr) != 0) err(11, 17); 645 if ((newstackaddr = malloc(newstacksize)) == NULL) err(11, 18); 646 if (mthread_attr_setstack(&tattr, newstackaddr, newstacksize) != EINVAL) 647 err(11, 19); 648 if (mthread_attr_getstack(&tattr, &stackaddr, &stacksize) != 0) err(11, 21); 649 if (stackaddr == newstackaddr) err(11, 22); 650 if (stacksize == newstacksize) err(11, 23); 651 if (mthread_attr_destroy(&tattr) != 0) err(11, 24); 652 free(newstackaddr); 653 654 /* Tell attribute to let the system allocate a stack for the thread and only 655 * dictate how big that stack should be (2 megabyte, not actually allocated 656 * yet). 657 */ 658 if (mthread_attr_init(&tattr) != 0) err(11, 25); 659 if (mthread_attr_setstack(&tattr, NULL /* System allocated */, 2*MEG) != 0) 660 err(11, 26); 661 if (mthread_attr_getstack(&tattr, &stackaddr, &stacksize) != 0) err(11, 27); 662 if (stackaddr != NULL) err(11, 28); 663 if (stacksize != 2*MEG) err(11, 29); 664 665 /* Use set/getstacksize to set and retrieve new stack sizes */ 666 stacksize = 0; 667 if (mthread_attr_getstacksize(&tattr, &stacksize) != 0) err(11, 30); 668 if (stacksize != 2*MEG) err(11, 31); 669 newstacksize = MEG; 670 if (mthread_attr_setstacksize(&tattr, newstacksize) != 0) err(11, 32); 671 if (mthread_attr_getstacksize(&tattr, &stacksize) != 0) err(11, 33); 672 if (stacksize != newstacksize) err(11, 34); 673 if (mthread_attr_destroy(&tattr) != 0) err(11, 35); 674 675 /* Perform same tests, but also actually use them in a thread */ 676 if (mthread_attr_init(&tattr) != 0) err(11, 36); 677 if (mthread_attr_setdetachstate(&tattr, MTHREAD_CREATE_DETACHED) != 0) 678 err(11, 37); 679 condition_mutex = &mu[0]; 680 if (mthread_mutex_init(condition_mutex, NULL) != 0) err(11, 38); 681 if (mthread_cond_init(&condition, NULL) != 0) err(11, 39); 682 if (mthread_mutex_lock(condition_mutex) != 0) err(11, 40); 683 if (mthread_create(&tid, &tattr, thread_f, NULL) != 0) err(11, 41); 684 /* Wait for thread_f to finish */ 685 if (mthread_cond_wait(&condition, condition_mutex) != 0) err(11, 42); 686 if (mthread_mutex_unlock(condition_mutex) != 0) err(11, 43); 687 if (th_f != 1) err(11, 44); 688 /* Joining a detached thread should fail */ 689 if (mthread_join(tid, NULL) == 0) err(11, 45); 690 if (mthread_attr_destroy(&tattr) != 0) err(11, 46); 691 692 /* Try telling the attribute how large the stack should be */ 693 if (mthread_attr_init(&tattr) != 0) err(11, 47); 694 if (mthread_attr_setstack(&tattr, NULL, 2 * MTHREAD_STACK_MIN) != 0) 695 err(11, 48); 696 if (mthread_mutex_lock(condition_mutex) != 0) err(11, 49); 697 if (mthread_create(&tid, &tattr, thread_g, NULL) != 0) err(11, 50); 698 /* Wait for thread_g to finish */ 699 if (mthread_cond_wait(&condition, condition_mutex) != 0) err(11, 51); 700 if (mthread_mutex_unlock(condition_mutex) != 0) err(11, 52); 701 if (th_g != 1) err(11, 53); 702 if (mthread_attr_setdetachstate(&tattr, MTHREAD_CREATE_DETACHED) != 0) 703 err(11, 54); /* Shouldn't affect the join below, as thread is already 704 * running as joinable. If this attribute should be 705 * modified after thread creation, use mthread_detach(). 706 */ 707 if (mthread_join(tid, NULL) != 0) err(11, 55); 708 if (mthread_attr_destroy(&tattr) != 0) err(11, 56); 709 710 /* Try telling the attribute how large the stack should be and where it is 711 * located. 712 */ 713 if (mthread_attr_init(&tattr) != 0) err(11, 57); 714 stacksize = 3 * MEG; 715 /* Make sure this test is meaningful. We have to verify that we actually 716 * use a custom stack. So we're going to allocate an array on the stack in 717 * thread_h that should at least be bigger than the default stack size 718 * allocated by the system. 719 */ 720 if (2 * MEG <= MTHREAD_STACK_MIN) err(11, 58); 721 if ((stackaddr = malloc(stacksize)) == NULL) err(11, 59); 722 /* Fill stack with pattern. We assume that the beginning of the stack 723 * should be overwritten with something and that the end should remain 724 * untouched. The thread will zero-fill around two-thirds of the stack with 725 * zeroes, so we can check if that's true. 726 */ 727 stackp = stackaddr; 728 no_ints = stacksize / sizeof(int); 729 for (i = 0; i < no_ints ; i++) 730 stackp[i] = MAGIC; 731 if (mthread_attr_setstack(&tattr, stackaddr, stacksize) != 0) err(11, 60); 732 if (mthread_mutex_lock(condition_mutex) != 0) err(11, 61); 733 if (mthread_create(&tid, &tattr, thread_h, (void *) &stacksize) != 0) 734 err(11, 62); 735 /* Wait for thread h to finish */ 736 if (mthread_cond_wait(&condition, condition_mutex) != 0) err(11, 63); 737 if (th_h != 1) err(11, 64); 738 if (mthread_mutex_unlock(condition_mutex) != 0) err(11, 65); 739 740 /* Verify stack hypothesis; we assume a stack is used from the top and grows 741 * downwards. 742 */ 743 #if defined(__i386__) || defined(__arm__) 744 if (stackp[0] != MAGIC) err(11, 66); /* End of the stack */ 745 for (i = no_ints - 1 - 16; i < no_ints; i++) 746 if (stackp[i] != MAGIC) stack_untouched = 0; 747 if (stack_untouched) err(11, 67); /* Beginning of the stack */ 748 if (stackp[no_ints / 2] != 0) err(11, 68);/*Zero half way through the stack*/ 749 #else 750 #error "Unsupported chip for this test" 751 #endif 752 753 if (mthread_join(tid, &status) != 0) err(11, 69); 754 if ((size_t) status != stacksize) err(11, 70); 755 if (mthread_attr_destroy(&tattr) != 0) err(11, 71); 756 if (mthread_mutex_destroy(condition_mutex) != 0) err(11, 72); 757 if (mthread_cond_destroy(&condition) != 0) err(11, 73); 758 free(stackaddr); 759 760 #ifdef MDEBUG 761 mthread_verify(); 762 #endif 763 } 764 765 /*===========================================================================* 766 * destr_a * 767 *===========================================================================*/ 768 static void destr_a(void *value) 769 { 770 int num; 771 772 num = (int) value; 773 774 /* This destructor must be called once for all of the values 1..4. */ 775 if (num <= 0 || num > 4) err(15, 1); 776 777 if (values[num - 1] != 1) err(15, 2); 778 779 values[num - 1] = 2; 780 } 781 782 /*===========================================================================* 783 * destr_b * 784 *===========================================================================*/ 785 static void destr_b(void *value) 786 { 787 /* This destructor must never trigger. */ 788 err(16, 1); 789 } 790 791 /*===========================================================================* 792 * key_a * 793 *===========================================================================*/ 794 static void *key_a(void *arg) 795 { 796 int i; 797 798 if (!first) mthread_yield(); 799 800 /* Each new threads gets NULL-initialized values. */ 801 for (i = 0; i < 5; i++) 802 if (mthread_getspecific(key[i]) != NULL) err(17, 1); 803 804 /* Make sure that the local values persist despite other threads' actions. */ 805 for (i = 1; i < 5; i++) 806 if (mthread_setspecific(key[i], (void *) i) != 0) err(17, 2); 807 808 mthread_yield(); 809 810 for (i = 1; i < 5; i++) 811 if (mthread_getspecific(key[i]) != (void *) i) err(17, 3); 812 813 mthread_yield(); 814 815 /* The other thread has deleted this key by now. */ 816 if (mthread_setspecific(key[3], NULL) != EINVAL) err(17, 4); 817 818 /* If a key's value is set to NULL, its destructor must not be called. */ 819 if (mthread_setspecific(key[4], NULL) != 0) err(17, 5); 820 return(NULL); 821 } 822 823 /*===========================================================================* 824 * key_b * 825 *===========================================================================*/ 826 static void *key_b(void *arg) 827 { 828 int i; 829 830 first = 1; 831 mthread_yield(); 832 833 /* Each new threads gets NULL-initialized values. */ 834 for (i = 0; i < 5; i++) 835 if (mthread_getspecific(key[i]) != NULL) err(18, 1); 836 837 for (i = 0; i < 4; i++) 838 if (mthread_setspecific(key[i], (void *) (i + 2)) != 0) err(18, 2); 839 840 mthread_yield(); 841 842 /* Deleting a key will not cause a call its destructor at any point. */ 843 if (mthread_key_delete(key[3]) != 0) err(18, 3); 844 845 mthread_exit(NULL); 846 return(NULL); 847 } 848 849 /*===========================================================================* 850 * key_c * 851 *===========================================================================*/ 852 static void *key_c(void *arg) 853 { 854 /* The only thing that this thread should do, is set a value. */ 855 if (mthread_setspecific(key[0], (void *) mthread_self()) != 0) err(19, 1); 856 857 mthread_yield(); 858 859 if (!mthread_equal((thread_t) mthread_getspecific(key[0]), mthread_self())) 860 err(19, 2); 861 return(NULL); 862 } 863 864 /*===========================================================================* 865 * test_keys * 866 *===========================================================================*/ 867 static void test_keys(void) 868 { 869 thread_t t[24]; 870 int i, j; 871 872 /* Make sure that we can create exactly MTHREAD_KEYS_MAX keys. */ 873 memset(key, 0, sizeof(key)); 874 875 for (i = 0; i < MTHREAD_KEYS_MAX; i++) { 876 if (mthread_key_create(&key[i], NULL) != 0) err(20, 1); 877 878 for (j = 0; j < i - 1; j++) 879 if (key[i] == key[j]) err(20, 2); 880 } 881 882 if (mthread_key_create(&key[i], NULL) != EAGAIN) err(20, 3); 883 884 for (i = 3; i < MTHREAD_KEYS_MAX; i++) 885 if (mthread_key_delete(key[i]) != 0) err(20, 4); 886 887 /* Test basic good and bad value assignment and retrieval. */ 888 if (mthread_setspecific(key[0], (void *) 1) != 0) err(20, 5); 889 if (mthread_setspecific(key[1], (void *) 2) != 0) err(20, 6); 890 if (mthread_setspecific(key[2], (void *) 3) != 0) err(20, 7); 891 if (mthread_setspecific(key[1], NULL) != 0) err(20, 8); 892 if (mthread_getspecific(key[0]) != (void *) 1) err(20, 9); 893 if (mthread_getspecific(key[1]) != NULL) err(20, 10); 894 if (mthread_getspecific(key[2]) != (void *) 3) err(20, 11); 895 if (mthread_setspecific(key[3], (void *) 4) != EINVAL) err(20, 12); 896 if (mthread_setspecific(key[3], NULL) != EINVAL) err(20, 13); 897 898 if (mthread_key_delete(key[1]) != 0) err(20, 14); 899 if (mthread_key_delete(key[2]) != 0) err(20, 15); 900 901 /* Test thread locality and destructors. */ 902 if (mthread_key_create(&key[1], destr_a) != 0) err(20, 16); 903 if (mthread_key_create(&key[2], destr_a) != 0) err(20, 17); 904 if (mthread_key_create(&key[3], destr_b) != 0) err(20, 18); 905 if (mthread_key_create(&key[4], destr_b) != 0) err(20, 19); 906 907 if (mthread_getspecific(key[2]) != NULL) err(20, 20); 908 909 for (i = 0; i < 4; i++) 910 values[i] = 1; 911 first = 0; 912 913 if (mthread_create(&t[0], NULL, key_a, NULL) != 0) err(20, 21); 914 if (mthread_create(&t[1], NULL, key_b, NULL) != 0) err(20, 22); 915 916 for (i = 0; i < 2; i++) 917 if (mthread_join(t[i], NULL) != 0) err(20, 23); 918 919 /* The destructors must have changed all these values now. */ 920 for (i = 0; i < 4; i++) 921 if (values[i] != 2) err(20, 24); 922 923 /* The original values must not have changed. */ 924 if (mthread_getspecific(key[0]) != (void *) 1) err(20, 25); 925 926 /* Deleting a deleted key should not cause any problems either. */ 927 if (mthread_key_delete(key[3]) != EINVAL) err(20, 26); 928 929 /* Make sure everything still works when using a larger number of threads. 930 * This should trigger reallocation code within libmthread's key handling. 931 */ 932 for (i = 0; i < 24; i++) 933 if (mthread_create(&t[i], NULL, key_c, NULL) != 0) err(20, 27); 934 935 for (i = 0; i < 24; i++) 936 if (mthread_join(t[i], NULL) != 0) err(20, 28); 937 } 938 939 /*===========================================================================* 940 * event_a * 941 *===========================================================================*/ 942 static void *event_a(void *arg) 943 { 944 VERIFY_EVENT(0, 0, 21, 1); 945 946 /* Wait for main thread to signal us */ 947 if (mthread_event_wait(&event) != 0) err(21, 2); 948 949 /* Mark state transition and wakeup thread b */ 950 event_a_step = 1; 951 if (mthread_event_fire(&event) != 0) err(21, 3); 952 mthread_yield(); 953 VERIFY_EVENT(1, 1, 21, 4); 954 955 /* Wait for main thread to signal again with fireall */ 956 if (mthread_event_wait(&event) != 0) err(21, 5); 957 958 /* Marks state transition and exit */ 959 event_a_step = 2; 960 return(NULL); 961 } 962 963 /*===========================================================================* 964 * event_b * 965 *===========================================================================*/ 966 static void *event_b(void *arg) 967 { 968 VERIFY_EVENT(0, 0, 22, 1); 969 970 /* Wait for thread a to signal us */ 971 if (mthread_event_wait(&event) != 0) err(22, 2); 972 VERIFY_EVENT(1, 0, 22, 3); 973 974 /* Mark state transition and wait again, this time for main thread */ 975 event_b_step = 1; 976 if (mthread_event_wait(&event) != 0) err(21, 5); 977 978 /* Marks state transition and exit */ 979 event_b_step = 2; 980 return(NULL); 981 } 982 983 /*===========================================================================* 984 * test_event * 985 *===========================================================================*/ 986 static void test_event(void) 987 { 988 thread_t t[2]; 989 int i; 990 991 if (mthread_event_init(&event) != 0) err(23, 1); 992 993 /* Try with faulty memory locations */ 994 if (mthread_event_wait(NULL) == 0) err(23, 2); 995 if (mthread_event_fire(NULL) == 0) err(23, 3); 996 997 /* create threads */ 998 if (mthread_create(&t[0], NULL, event_a, NULL) != 0) err(23, 4); 999 if (mthread_create(&t[1], NULL, event_b, NULL) != 0) err(23, 5); 1000 1001 /* wait for them to block on event */ 1002 mthread_yield_all(); 1003 VERIFY_EVENT(0, 0, 23, 6); 1004 1005 /* Fire event to wakeup thread a */ 1006 if (mthread_event_fire(&event) != 0) err(23, 7); 1007 mthread_yield_all(); 1008 VERIFY_EVENT(1, 1, 23, 6); 1009 1010 /* Fire all to wakeup both a and b */ 1011 if (mthread_event_fire_all(&event) != 0) err(23, 7); 1012 mthread_yield_all(); 1013 VERIFY_EVENT(2, 2, 23, 8); 1014 1015 /* We are done here */ 1016 for (i = 0; i < 2; i++) 1017 if (mthread_join(t[i], NULL) != 0) err(23, 9); 1018 1019 if (mthread_event_destroy(&event) != 0) err(23, 10); 1020 } 1021 1022 /*===========================================================================* 1023 * rwlock_a * 1024 *===========================================================================*/ 1025 static void *rwlock_a(void *arg) 1026 { 1027 /* acquire read lock */ 1028 VERIFY_RWLOCK(0, 0, 24, 1); 1029 if (mthread_rwlock_rdlock(&rwlock) != 0) err(24, 2); 1030 rwlock_a_step = 1; 1031 mthread_yield(); 1032 1033 /* release read lock */ 1034 VERIFY_RWLOCK(1, 1, 24, 3); 1035 if (mthread_rwlock_unlock(&rwlock) != 0) err(24, 4); 1036 rwlock_a_step = 2; 1037 1038 /* get write lock */ 1039 if (mthread_rwlock_wrlock(&rwlock) != 0) err(24, 5); 1040 rwlock_a_step = 3; 1041 VERIFY_RWLOCK(3, 2, 24, 6); 1042 1043 /* release write lock */ 1044 if (mthread_rwlock_unlock(&rwlock) != 0) err(24, 7); 1045 mthread_yield(); 1046 1047 VERIFY_RWLOCK(3, 3, 24, 8); 1048 1049 return(NULL); 1050 } 1051 1052 /*===========================================================================* 1053 * rwlock_b * 1054 *===========================================================================*/ 1055 static void *rwlock_b(void *arg) 1056 { 1057 /* Step 1: acquire the read lock */ 1058 VERIFY_RWLOCK(1, 0, 25, 1); 1059 if (mthread_rwlock_rdlock(&rwlock) != 0) err(25, 2); 1060 rwlock_b_step = 1; 1061 mthread_yield(); 1062 1063 /* We return back with first thread blocked on wrlock */ 1064 VERIFY_RWLOCK(2, 1, 25, 3); 1065 rwlock_b_step = 2; 1066 1067 /* Release read lock and acquire write lock */ 1068 if (mthread_rwlock_unlock(&rwlock) != 0) err(25, 4); 1069 if (mthread_rwlock_wrlock(&rwlock) != 0) err(25, 5); 1070 rwlock_b_step = 3; 1071 1072 VERIFY_RWLOCK(3, 3, 25, 6); 1073 if (mthread_rwlock_unlock(&rwlock) != 0) err(25, 6); 1074 1075 return(NULL); 1076 } 1077 1078 /*===========================================================================* 1079 * test_rwlock * 1080 *===========================================================================*/ 1081 static void test_rwlock(void) 1082 { 1083 thread_t t[2]; 1084 int i; 1085 1086 if (mthread_rwlock_init(&rwlock) != 0) err(26, 1); 1087 1088 /* Try with faulty memory locations */ 1089 if (mthread_rwlock_rdlock(NULL) == 0) err(26, 2); 1090 if (mthread_rwlock_wrlock(NULL) == 0) err(26, 3); 1091 if (mthread_rwlock_unlock(NULL) == 0) err(26, 4); 1092 1093 /* Create the threads and start testing */ 1094 if (mthread_create(&t[0], NULL, rwlock_a, NULL) != 0) err(26, 5); 1095 if (mthread_create(&t[1], NULL, rwlock_b, NULL) != 0) err(26, 6); 1096 1097 mthread_yield_all(); 1098 1099 for (i = 0; i < 2; i++) 1100 if (mthread_join(t[i], NULL) != 0) err(26, 7); 1101 1102 if (mthread_rwlock_destroy(&rwlock) != 0) err(26, 8); 1103 } 1104 1105 1106 /*===========================================================================* 1107 * main * 1108 *===========================================================================*/ 1109 int main(void) 1110 { 1111 errct = 0; 1112 th_a = th_b = th_c = th_d = th_e = th_f = th_g = th_h = 0; 1113 mutex_a_step = mutex_b_step = mutex_c_step = 0; 1114 event_a_step = event_b_step = 0; 1115 rwlock_a_step = rwlock_b_step = 0; 1116 once = MTHREAD_ONCE_INIT; 1117 1118 start(59); 1119 test_scheduling(); 1120 test_mutex(); 1121 test_event(); 1122 test_rwlock(); 1123 test_condition(); 1124 test_attributes(); 1125 test_keys(); 1126 quit(); 1127 return(0); /* Not reachable */ 1128 } 1129 1130