xref: /minix/minix/tests/test59.c (revision cd34841d)
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