Drop main() prototype. Syncs with NetBSD-8
[minix.git] / minix / tests / test59.c
blobf077ec70e1ef650f4c1608ab087f2c55db57e94f
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>
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
17 int max_error = 5;
18 #include "common.h"
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;
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 { \
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)
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)
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 /*===========================================================================*
82 * thread_a *
83 *===========================================================================*/
84 static void *thread_a(void *arg) {
85 th_a++;
86 return(NULL);
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);
100 /*===========================================================================*
101 * thread_c *
102 *===========================================================================*/
103 static void *thread_c(void *arg) {
104 th_c++;
105 return(NULL);
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);
119 /*===========================================================================*
120 * thread_e *
121 *===========================================================================*/
122 static void thread_e(void) {
123 th_e++;
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);
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);
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);
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. */
177 subtest = sub;
178 e(error);
182 /*===========================================================================*
183 * test_scheduling *
184 *===========================================================================*/
185 static void test_scheduling(void)
187 unsigned int i;
188 thread_t t[7];
190 #ifdef MDEBUG
191 mthread_verify();
192 #endif
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);
201 mthread_yield();
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);
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*/
223 #ifdef MDEBUG
224 mthread_verify();
225 #endif
226 if (mthread_create(NULL, NULL, NULL, NULL) == 0) err(1, 18);
227 mthread_yield();
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();
241 #ifdef MDEBUG
242 mthread_verify();
243 #endif
247 /*===========================================================================*
248 * mutex_a *
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) {
265 err(3, 4);
266 mthread_mutex_unlock(&mu2);
269 if (mthread_mutex_trylock(&mu2) != EINVAL) {
270 err(3, 6);
271 mthread_mutex_unlock(&mu2);
273 #endif
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.
283 VERIFY_MUTEX(1, 0, 0, 3, 13);
285 if (mthread_mutex_unlock(&mu[0]) != 0) err(3, 14);
286 mutex_a_step = 2;
287 mthread_yield();
289 VERIFY_MUTEX(2, 1, 0, 3, 15);
290 if (mthread_mutex_unlock(&mu[1]) != 0) err(3, 16);
291 mutex_a_step = 3;
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);
299 return(NULL);
303 /*===========================================================================*
304 * mutex_b *
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);
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);
329 if (mthread_mutex_unlock(&mu[0]) != 0) err(4, 7);
330 mutex_b_step = 3;
331 mthread_yield();
333 if (mthread_mutex_unlock(&mu[1]) != 0) err(4, 8);
334 mutex_b_step = 4;
335 return(NULL);
339 /*===========================================================================*
340 * mutex_c *
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);
348 mutex_c_step = 1;
349 VERIFY_MUTEX(3, 1, 1, 5, 3);
350 mthread_yield();
351 VERIFY_MUTEX(3, 1, 1, 5, 4);
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);
361 if (mthread_mutex_unlock(&mu[0]) != 0) err(5, 9);
362 mutex_c_step = 4;
363 return(NULL);
367 /*===========================================================================*
368 * test_mutex *
369 *===========================================================================*/
370 static void test_mutex(void)
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);
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);
407 #ifdef MDEBUG
408 mthread_verify();
409 #endif
413 /*===========================================================================*
414 * cond_a *
415 *===========================================================================*/
416 static void *cond_a(void *arg)
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);
426 if (mthread_mutex_unlock(condition_mutex) != 0) err(6, 3);
428 mthread_yield();
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);
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);
451 #endif
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);
462 /*===========================================================================*
463 * cond_b *
464 *===========================================================================*/
465 static void *cond_b(void *arg)
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);
474 mthread_yield();
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);
481 if (count >= ROUNDS) break;
484 if (!(did_count >= count - (THRESH2 - THRESH1 + 1))) err(7, 6);
486 return(NULL);
489 /*===========================================================================*
490 * cond_broadcast *
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);
502 count++;
503 if (mthread_mutex_unlock(count_mutex) != 0) err(9, 5);
504 return(NULL);
507 /*===========================================================================*
508 * test_condition *
509 *===========================================================================*/
510 static void test_condition(void)
512 #define NTHREADS 10
513 int i;
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.
525 #ifdef MDEBUG
526 mthread_verify();
527 #endif
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;
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);
549 #endif
551 #ifdef MDEBUG
552 mthread_verify();
553 #endif
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.
569 mthread_yield();
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);
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);
588 #endif
590 #ifdef MDEBUG
591 mthread_verify();
592 #endif
595 /*===========================================================================*
596 * test_attributes *
597 *===========================================================================*/
598 static void test_attributes(void)
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;
608 #ifdef MDEBUG
609 mthread_verify();
610 #endif
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)
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);
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;
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);
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).
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);
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);
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);
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().
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
711 * located.
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.
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.
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);
740 /* Verify stack hypothesis; we assume a stack is used from the top and grows
741 * downwards.
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
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);
760 #ifdef MDEBUG
761 mthread_verify();
762 #endif
765 /*===========================================================================*
766 * destr_a *
767 *===========================================================================*/
768 static void destr_a(void *value)
770 int num;
772 num = (int) 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);
779 values[num - 1] = 2;
782 /*===========================================================================*
783 * destr_b *
784 *===========================================================================*/
785 static void destr_b(void *value)
787 /* This destructor must never trigger. */
788 err(16, 1);
791 /*===========================================================================*
792 * key_a *
793 *===========================================================================*/
794 static void *key_a(void *arg)
796 int i;
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);
808 mthread_yield();
810 for (i = 1; i < 5; i++)
811 if (mthread_getspecific(key[i]) != (void *) i) err(17, 3);
813 mthread_yield();
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);
820 return(NULL);
823 /*===========================================================================*
824 * key_b *
825 *===========================================================================*/
826 static void *key_b(void *arg)
828 int i;
830 first = 1;
831 mthread_yield();
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);
840 mthread_yield();
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);
845 mthread_exit(NULL);
846 return(NULL);
849 /*===========================================================================*
850 * key_c *
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);
857 mthread_yield();
859 if (!mthread_equal((thread_t) mthread_getspecific(key[0]), mthread_self()))
860 err(19, 2);
861 return(NULL);
864 /*===========================================================================*
865 * test_keys *
866 *===========================================================================*/
867 static void test_keys(void)
869 thread_t t[24];
870 int i, j;
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++)
910 values[i] = 1;
911 first = 0;
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 /*===========================================================================*
940 * event_a *
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 */
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);
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 */
959 event_a_step = 2;
960 return(NULL);
963 /*===========================================================================*
964 * event_b *
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 */
975 event_b_step = 1;
976 if (mthread_event_wait(&event) != 0) err(21, 5);
978 /* Marks state transition and exit */
979 event_b_step = 2;
980 return(NULL);
983 /*===========================================================================*
984 * test_event *
985 *===========================================================================*/
986 static void test_event(void)
988 thread_t t[2];
989 int i;
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);
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);
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 /*===========================================================================*
1023 * rwlock_a *
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);
1030 rwlock_a_step = 1;
1031 mthread_yield();
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;
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);
1043 /* release write lock */
1044 if (mthread_rwlock_unlock(&rwlock) != 0) err(24, 7);
1045 mthread_yield();
1047 VERIFY_RWLOCK(3, 3, 24, 8);
1049 return(NULL);
1052 /*===========================================================================*
1053 * rwlock_b *
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);
1060 rwlock_b_step = 1;
1061 mthread_yield();
1063 /* We return back with first thread blocked on wrlock */
1064 VERIFY_RWLOCK(2, 1, 25, 3);
1065 rwlock_b_step = 2;
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;
1072 VERIFY_RWLOCK(3, 3, 25, 6);
1073 if (mthread_rwlock_unlock(&rwlock) != 0) err(25, 6);
1075 return(NULL);
1078 /*===========================================================================*
1079 * test_rwlock *
1080 *===========================================================================*/
1081 static void test_rwlock(void)
1083 thread_t t[2];
1084 int i;
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 /*===========================================================================*
1107 * main *
1108 *===========================================================================*/
1109 int main(void)
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;
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 */