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. */
5 #include <minix/mthread.h>
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
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
;
25 static cond_t condition
;
26 static mutex_t
*count_mutex
, *condition_mutex
;
28 static key_t key
[MTHREAD_KEYS_MAX
+1];
32 static int event_a_step
, event_b_step
;
33 static rwlock_t rwlock
;
34 static int rwlock_a_step
, rwlock_b_step
;
36 #define VERIFY_RWLOCK(a, b, esub, eno) \
37 GEN_VERIFY(rwlock_a_step, a, rwlock_b_step, b, esub, eno)
39 #define VERIFY_EVENT(a, b, esub, eno) \
40 GEN_VERIFY(event_a_step, a, event_b_step, b, esub, eno)
42 #define GEN_VERIFY(acta, a, actb, b, esub, eno) do { \
44 printf("Expected %d %d, got: %d %d\n", \
47 } else if (actb != b) err(esub, eno); \
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); \
55 } else if (mutex_b_step != b) err(esub, eno); \
56 else if (mutex_c_step != c) err(esub, eno); \
62 #define MAGIC ((signed) 0xb4a3f1c2)
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
);
81 /*===========================================================================*
83 *===========================================================================*/
84 static void *thread_a(void *arg
) {
90 /*===========================================================================*
92 *===========================================================================*/
93 static void *thread_b(void *arg
) {
95 if (mthread_once(&once
, thread_e
) != 0) err(10, 1);
100 /*===========================================================================*
102 *===========================================================================*/
103 static void *thread_c(void *arg
) {
109 /*===========================================================================*
111 *===========================================================================*/
112 static void *thread_d(void *arg
) {
114 mthread_exit(NULL
); /* Thread wants to stop running */
119 /*===========================================================================*
121 *===========================================================================*/
122 static void thread_e(void) {
127 /*===========================================================================*
129 *===========================================================================*/
130 static void *thread_f(void *arg
) {
131 if (mthread_mutex_lock(condition_mutex
) != 0) err(12, 1);
133 if (mthread_cond_signal(&condition
) != 0) err(12, 2);
134 if (mthread_mutex_unlock(condition_mutex
) != 0) err(12, 3);
139 /*===========================================================================*
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 */
147 if (mthread_cond_signal(&condition
) != 0) err(13, 2);
148 if (mthread_mutex_unlock(condition_mutex
) != 0) err(13, 3);
153 /*===========================================================================*
155 *===========================================================================*/
156 static void *thread_h(void *arg
) {
157 char bigarray
[2 * MEG
];
159 if (mthread_mutex_lock(condition_mutex
) != 0) err(14, 1);
160 memset(bigarray
, '\0', 2 * MEG
); /* Actually allocate it */
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
);
170 /*===========================================================================*
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. */
182 /*===========================================================================*
184 *===========================================================================*/
185 static void test_scheduling(void)
193 th_a
= th_b
= th_c
= th_d
= th_e
= 0;
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);
203 if (mthread_create(&t
[4], NULL
, thread_c
, NULL
) != 0) err(1, 6);
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);
209 if (mthread_once(&once
, thread_e
) != 0) err(1, 9);
210 if (mthread_once(&once
, thread_e
) != 0) err(1, 10);
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);
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*/
226 if (mthread_create(NULL
, NULL
, NULL
, NULL
) == 0) err(1, 18);
232 if (mthread_create(&t
[6], NULL
, NULL
, NULL
) == 0) err(1, 19);
237 if (mthread_join(0xc0ffee, NULL
) == 0) err(1, 20);
247 /*===========================================================================*
249 *===========================================================================*/
250 static void *mutex_a(void *arg
)
252 mutex_t
*mu
= (mutex_t
*) arg
;
254 VERIFY_MUTEX(0, 0, 0, 3, 1);
255 if (mthread_mutex_lock(&mu
[0]) != 0) err(3, 2);
257 /* Trying to acquire lock again should fail with EDEADLK */
258 if (mthread_mutex_lock(&mu
[0]) != EDEADLK
) err(3, 2);
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
) {
266 mthread_mutex_unlock(&mu2
);
269 if (mthread_mutex_trylock(&mu2
) != EINVAL
) {
271 mthread_mutex_unlock(&mu2
);
275 if (mthread_mutex_trylock(&mu
[1]) != 0) err(3, 8);
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
283 VERIFY_MUTEX(1, 0, 0, 3, 13);
285 if (mthread_mutex_unlock(&mu
[0]) != 0) err(3, 14);
289 VERIFY_MUTEX(2, 1, 0, 3, 15);
290 if (mthread_mutex_unlock(&mu
[1]) != 0) err(3, 16);
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);
298 if (mthread_mutex_unlock(&mu
[2]) != 0) err(3, 20);
303 /*===========================================================================*
305 *===========================================================================*/
306 static void *mutex_b(void *arg
)
308 mutex_t
*mu
= (mutex_t
*) arg
;
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.
314 VERIFY_MUTEX(1, 0, 0, 4, 1);
315 if (mthread_mutex_unlock(&mu
[0]) != EPERM
) err(4, 2);
317 /* Probing mu[0] to lock it should tell us it's locked */
318 if (mthread_mutex_trylock(&mu
[0]) != EBUSY
) err(4, 4);
320 if (mthread_mutex_lock(&mu
[0]) != 0) err(4, 5);
322 VERIFY_MUTEX(2, 1, 0, 4, 6);
323 if (mthread_mutex_lock(&mu
[1]) != 0) err(4, 6);
325 VERIFY_MUTEX(3, 2, 2, 4, 7);
327 VERIFY_MUTEX(3, 2, 2, 4, 8);
329 if (mthread_mutex_unlock(&mu
[0]) != 0) err(4, 7);
333 if (mthread_mutex_unlock(&mu
[1]) != 0) err(4, 8);
339 /*===========================================================================*
341 *===========================================================================*/
342 static void *mutex_c(void *arg
)
344 mutex_t
*mu
= (mutex_t
*) arg
;
346 VERIFY_MUTEX(1, 0, 0, 5, 1);
347 if (mthread_mutex_lock(&mu
[1]) != 0) err(5, 2);
349 VERIFY_MUTEX(3, 1, 1, 5, 3);
351 VERIFY_MUTEX(3, 1, 1, 5, 4);
353 if (mthread_mutex_unlock(&mu
[1]) != 0) err(5, 5);
355 if (mthread_mutex_lock(&mu
[0]) != 0) err(5, 6);
357 VERIFY_MUTEX(3, 3, 3, 5, 7);
359 VERIFY_MUTEX(3, 4, 3, 5, 8);
361 if (mthread_mutex_unlock(&mu
[0]) != 0) err(5, 9);
367 /*===========================================================================*
369 *===========================================================================*/
370 static void test_mutex(void)
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);
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);
385 if (mthread_mutex_lock(&mu
[2]) != 0) err(2, 6);
387 mthread_yield_all(); /* Should result in a RUNNABLE mutex_a, and a blocked
388 * on mutex mutex_b and mutex_c.
391 VERIFY_MUTEX(1, 0, 0, 2, 7); /* err(2, 7) */
392 if (mthread_mutex_unlock(&mu
[2]) != 0) err(2, 8);
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.
398 VERIFY_MUTEX(2, 0, 0, 2, 9);
400 for (i
= 0; i
< (sizeof(t
) / sizeof(thread_t
)); i
++)
401 if (mthread_join(t
[i
], NULL
) != 0) err(2, 10);
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);
413 /*===========================================================================*
415 *===========================================================================*/
416 static void *cond_a(void *arg
)
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)
426 if (mthread_mutex_unlock(condition_mutex
) != 0) err(6, 3);
430 if (mthread_mutex_lock(count_mutex
) != 0) err(6, 4);
433 if (mthread_mutex_unlock(count_mutex
) != 0) err(6, 5);
435 if (count
>= ROUNDS
) break;
437 if (!(did_count
<= count
- (THRESH2
- THRESH1
+ 1))) err(6, 6);
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);
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);
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);
462 /*===========================================================================*
464 *===========================================================================*/
465 static void *cond_b(void *arg
)
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);
476 if (mthread_mutex_lock(count_mutex
) != 0) err(7, 4);
479 if (mthread_mutex_unlock(count_mutex
) != 0) err(7, 5);
481 if (count
>= ROUNDS
) break;
484 if (!(did_count
>= count
- (THRESH2
- THRESH1
+ 1))) err(7, 6);
489 /*===========================================================================*
491 *===========================================================================*/
492 static void *cond_broadcast(void *arg
)
494 if (mthread_mutex_lock(condition_mutex
) != 0) err(9, 1);
496 while(!condition_met
)
497 if (mthread_cond_wait(&condition
, condition_mutex
) != 0) err(9, 2);
499 if (mthread_mutex_unlock(condition_mutex
) != 0) err(9, 3);
501 if (mthread_mutex_lock(count_mutex
) != 0) err(9, 4);
503 if (mthread_mutex_unlock(count_mutex
) != 0) err(9, 5);
507 /*===========================================================================*
509 *===========================================================================*/
510 static void test_condition(void)
514 thread_t t
[2], s
[NTHREADS
];
515 count_mutex
= &mu
[0];
516 condition_mutex
= &mu
[1];
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.
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);
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);
537 for (i
= 0; i
< (sizeof(t
) / sizeof(thread_t
)); i
++)
538 if (mthread_join(t
[i
], NULL
) != 0) err(8, 6);
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);
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);
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;
562 for (i
= 0; i
< NTHREADS
; i
++)
563 if (mthread_create(&s
[i
], NULL
, cond_broadcast
, NULL
) != 0) err(8, 14);
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.
571 if (mthread_mutex_lock(condition_mutex
) != 0) err(8, 15);
573 if (mthread_cond_broadcast(&condition
) != 0) err(8, 16);
574 if (mthread_mutex_unlock(condition_mutex
) != 0) err(8, 17);
576 for (i
= 0; i
< (sizeof(s
) / sizeof(thread_t
)); i
++)
577 if (mthread_join(s
[i
], NULL
) != 0) err(8, 18);
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);
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);
595 /*===========================================================================*
597 *===========================================================================*/
598 static void test_attributes(void)
602 int detachstate
= -1, status
= 0;
603 unsigned int i
, no_ints
, stack_untouched
= 1;
604 void *stackaddr
, *newstackaddr
;
606 size_t stacksize
, newstacksize
;
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);
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)
625 newstacksize
= (size_t) MEG
;
626 if ((newstackaddr
= malloc(newstacksize
)) == NULL
) err(11, 9);
627 if (mthread_attr_setstack(&tattr
, newstackaddr
, newstacksize
) != 0)
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);
638 /* Try to allocate too small a stack; it should fail and the attribute
639 * values should remain as is.
641 newstacksize
= MTHREAD_STACK_MIN
- 1;
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
)
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);
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
658 if (mthread_attr_init(&tattr
) != 0) err(11, 25);
659 if (mthread_attr_setstack(&tattr
, NULL
/* System allocated */, 2*MEG
) != 0)
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);
665 /* Use set/getstacksize to set and retrieve new stack sizes */
667 if (mthread_attr_getstacksize(&tattr
, &stacksize
) != 0) err(11, 30);
668 if (stacksize
!= 2*MEG
) err(11, 31);
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);
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)
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);
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)
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().
707 if (mthread_join(tid
, NULL
) != 0) err(11, 55);
708 if (mthread_attr_destroy(&tattr
) != 0) err(11, 56);
710 /* Try telling the attribute how large the stack should be and where it is
713 if (mthread_attr_init(&tattr
) != 0) err(11, 57);
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.
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.
728 no_ints
= stacksize
/ sizeof(int);
729 for (i
= 0; i
< no_ints
; i
++)
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)
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);
740 /* Verify stack hypothesis; we assume a stack is used from the top and grows
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*/
750 #error "Unsupported chip for this test"
753 if (mthread_join(tid
, (void *) &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);
765 /*===========================================================================*
767 *===========================================================================*/
768 static void destr_a(void *value
)
774 /* This destructor must be called once for all of the values 1..4. */
775 if (num
<= 0 || num
> 4) err(15, 1);
777 if (values
[num
- 1] != 1) err(15, 2);
782 /*===========================================================================*
784 *===========================================================================*/
785 static void destr_b(void *value
)
787 /* This destructor must never trigger. */
791 /*===========================================================================*
793 *===========================================================================*/
794 static void *key_a(void *arg
)
798 if (!first
) mthread_yield();
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);
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);
810 for (i
= 1; i
< 5; i
++)
811 if (mthread_getspecific(key
[i
]) != (void *) i
) err(17, 3);
815 /* The other thread has deleted this key by now. */
816 if (mthread_setspecific(key
[3], NULL
) != EINVAL
) err(17, 4);
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);
823 /*===========================================================================*
825 *===========================================================================*/
826 static void *key_b(void *arg
)
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);
837 for (i
= 0; i
< 4; i
++)
838 if (mthread_setspecific(key
[i
], (void *) (i
+ 2)) != 0) err(18, 2);
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);
849 /*===========================================================================*
851 *===========================================================================*/
852 static void *key_c(void *arg
)
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);
859 if (!mthread_equal((thread_t
) mthread_getspecific(key
[0]), mthread_self()))
864 /*===========================================================================*
866 *===========================================================================*/
867 static void test_keys(void)
872 /* Make sure that we can create exactly MTHREAD_KEYS_MAX keys. */
873 memset(key
, 0, sizeof(key
));
875 for (i
= 0; i
< MTHREAD_KEYS_MAX
; i
++) {
876 if (mthread_key_create(&key
[i
], NULL
) != 0) err(20, 1);
878 for (j
= 0; j
< i
- 1; j
++)
879 if (key
[i
] == key
[j
]) err(20, 2);
882 if (mthread_key_create(&key
[i
], NULL
) != EAGAIN
) err(20, 3);
884 for (i
= 3; i
< MTHREAD_KEYS_MAX
; i
++)
885 if (mthread_key_delete(key
[i
]) != 0) err(20, 4);
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);
898 if (mthread_key_delete(key
[1]) != 0) err(20, 14);
899 if (mthread_key_delete(key
[2]) != 0) err(20, 15);
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);
907 if (mthread_getspecific(key
[2]) != NULL
) err(20, 20);
909 for (i
= 0; i
< 4; i
++)
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);
916 for (i
= 0; i
< 2; i
++)
917 if (mthread_join(t
[i
], NULL
) != 0) err(20, 23);
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);
923 /* The original values must not have changed. */
924 if (mthread_getspecific(key
[0]) != (void *) 1) err(20, 25);
926 /* Deleting a deleted key should not cause any problems either. */
927 if (mthread_key_delete(key
[3]) != EINVAL
) err(20, 26);
929 /* Make sure everything still works when using a larger number of threads.
930 * This should trigger reallocation code within libmthread's key handling.
932 for (i
= 0; i
< 24; i
++)
933 if (mthread_create(&t
[i
], NULL
, key_c
, NULL
) != 0) err(20, 27);
935 for (i
= 0; i
< 24; i
++)
936 if (mthread_join(t
[i
], NULL
) != 0) err(20, 28);
939 /*===========================================================================*
941 *===========================================================================*/
942 static void *event_a(void *arg
)
944 VERIFY_EVENT(0, 0, 21, 1);
946 /* Wait for main thread to signal us */
947 if (mthread_event_wait(&event
) != 0) err(21, 2);
949 /* Mark state transition and wakeup thread b */
951 if (mthread_event_fire(&event
) != 0) err(21, 3);
953 VERIFY_EVENT(1, 1, 21, 4);
955 /* Wait for main thread to signal again with fireall */
956 if (mthread_event_wait(&event
) != 0) err(21, 5);
958 /* Marks state transition and exit */
963 /*===========================================================================*
965 *===========================================================================*/
966 static void *event_b(void *arg
)
968 VERIFY_EVENT(0, 0, 22, 1);
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);
974 /* Mark state transition and wait again, this time for main thread */
976 if (mthread_event_wait(&event
) != 0) err(21, 5);
978 /* Marks state transition and exit */
983 /*===========================================================================*
985 *===========================================================================*/
986 static void test_event(void)
991 if (mthread_event_init(&event
) != 0) err(23, 1);
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);
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);
1001 /* wait for them to block on event */
1002 mthread_yield_all();
1003 VERIFY_EVENT(0, 0, 23, 6);
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);
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);
1015 /* We are done here */
1016 for (i
= 0; i
< 2; i
++)
1017 if (mthread_join(t
[i
], NULL
) != 0) err(23, 9);
1019 if (mthread_event_destroy(&event
) != 0) err(23, 10);
1022 /*===========================================================================*
1024 *===========================================================================*/
1025 static void *rwlock_a(void *arg
)
1027 /* acquire read lock */
1028 VERIFY_RWLOCK(0, 0, 24, 1);
1029 if (mthread_rwlock_rdlock(&rwlock
) != 0) err(24, 2);
1033 /* release read lock */
1034 VERIFY_RWLOCK(1, 1, 24, 3);
1035 if (mthread_rwlock_unlock(&rwlock
) != 0) err(24, 4);
1038 /* get write lock */
1039 if (mthread_rwlock_wrlock(&rwlock
) != 0) err(24, 5);
1041 VERIFY_RWLOCK(3, 2, 24, 6);
1043 /* release write lock */
1044 if (mthread_rwlock_unlock(&rwlock
) != 0) err(24, 7);
1047 VERIFY_RWLOCK(3, 3, 24, 8);
1052 /*===========================================================================*
1054 *===========================================================================*/
1055 static void *rwlock_b(void *arg
)
1057 /* Step 1: acquire the read lock */
1058 VERIFY_RWLOCK(1, 0, 25, 1);
1059 if (mthread_rwlock_rdlock(&rwlock
) != 0) err(25, 2);
1063 /* We return back with first thread blocked on wrlock */
1064 VERIFY_RWLOCK(2, 1, 25, 3);
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);
1072 VERIFY_RWLOCK(3, 3, 25, 6);
1073 if (mthread_rwlock_unlock(&rwlock
) != 0) err(25, 6);
1078 /*===========================================================================*
1080 *===========================================================================*/
1081 static void test_rwlock(void)
1086 if (mthread_rwlock_init(&rwlock
) != 0) err(26, 1);
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);
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);
1097 mthread_yield_all();
1099 for (i
= 0; i
< 2; i
++)
1100 if (mthread_join(t
[i
], NULL
) != 0) err(26, 7);
1102 if (mthread_rwlock_destroy(&rwlock
) != 0) err(26, 8);
1106 /*===========================================================================*
1108 *===========================================================================*/
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
;
1128 return(0); /* Not reachable */