xref: /minix3/minix/tests/test59.c (revision d26b52b7cfc4f2c73cf7d42ddada702c1c6c51a2)
1433d6423SLionel Sambuc /* Test the mthreads library. When the library is compiled with -DMDEBUG, you
2433d6423SLionel Sambuc  * have to compile this test with -DMDEBUG as well or it won't link. MDEBUG
3433d6423SLionel Sambuc  * lets you check the internal integrity of the library. */
4433d6423SLionel Sambuc #include <stdio.h>
5433d6423SLionel Sambuc #include <minix/mthread.h>
6433d6423SLionel Sambuc #include <signal.h>
7433d6423SLionel Sambuc 
8433d6423SLionel Sambuc #define thread_t mthread_thread_t
9433d6423SLionel Sambuc #define mutex_t mthread_mutex_t
10433d6423SLionel Sambuc #define cond_t mthread_cond_t
11433d6423SLionel Sambuc #define once_t mthread_once_t
12433d6423SLionel Sambuc #define attr_t mthread_attr_t
13433d6423SLionel Sambuc #define key_t mthread_key_t
14433d6423SLionel Sambuc #define event_t mthread_event_t
15433d6423SLionel Sambuc #define rwlock_t mthread_rwlock_t
16433d6423SLionel Sambuc 
17433d6423SLionel Sambuc int max_error = 5;
18433d6423SLionel Sambuc #include "common.h"
19433d6423SLionel Sambuc 
20433d6423SLionel Sambuc 
21433d6423SLionel Sambuc static int count, condition_met;
22433d6423SLionel Sambuc static int th_a, th_b, th_c, th_d, th_e, th_f, th_g, th_h;
23433d6423SLionel Sambuc static int mutex_a_step, mutex_b_step, mutex_c_step;
24433d6423SLionel Sambuc static mutex_t mu[3];
25433d6423SLionel Sambuc static cond_t condition;
26433d6423SLionel Sambuc static mutex_t *count_mutex, *condition_mutex;
27433d6423SLionel Sambuc static once_t once;
28433d6423SLionel Sambuc static key_t key[MTHREAD_KEYS_MAX+1];
29433d6423SLionel Sambuc static int values[4];
30433d6423SLionel Sambuc static int first;
31433d6423SLionel Sambuc static event_t event;
32433d6423SLionel Sambuc static int event_a_step, event_b_step;
33433d6423SLionel Sambuc static rwlock_t rwlock;
34433d6423SLionel Sambuc static int rwlock_a_step, rwlock_b_step;
35433d6423SLionel Sambuc 
36433d6423SLionel Sambuc #define VERIFY_RWLOCK(a, b, esub, eno) \
37433d6423SLionel Sambuc 	GEN_VERIFY(rwlock_a_step, a, rwlock_b_step, b, esub, eno)
38433d6423SLionel Sambuc 
39433d6423SLionel Sambuc #define VERIFY_EVENT(a, b, esub, eno) \
40433d6423SLionel Sambuc 	GEN_VERIFY(event_a_step, a, event_b_step, b, esub, eno)
41433d6423SLionel Sambuc 
42433d6423SLionel Sambuc #define GEN_VERIFY(acta, a, actb, b, esub, eno)	do { \
43433d6423SLionel Sambuc 	if (acta != a) { \
44433d6423SLionel Sambuc 		printf("Expected %d %d, got: %d %d\n", \
45433d6423SLionel Sambuc 			a, b, acta, actb); \
46433d6423SLionel Sambuc 		err(esub, eno); \
47433d6423SLionel Sambuc 	} else if (actb != b) err(esub, eno); \
48433d6423SLionel Sambuc 					} while(0)
49433d6423SLionel Sambuc 
50433d6423SLionel Sambuc #define VERIFY_MUTEX(a,b,c,esub,eno)	do { \
51433d6423SLionel Sambuc 	if (mutex_a_step != a) { \
52433d6423SLionel Sambuc 		printf("Expected %d %d %d, got: %d %d %d\n", \
53433d6423SLionel Sambuc 			a, b, c, mutex_a_step, mutex_b_step, mutex_c_step); \
54433d6423SLionel Sambuc 		err(esub, eno); \
55433d6423SLionel Sambuc 	} else if (mutex_b_step != b) err(esub, eno); \
56433d6423SLionel Sambuc 	else if (mutex_c_step != c) err(esub, eno); \
57433d6423SLionel Sambuc 					} while(0)
58433d6423SLionel Sambuc #define ROUNDS 14
59433d6423SLionel Sambuc #define THRESH1 3
60433d6423SLionel Sambuc #define THRESH2 8
61433d6423SLionel Sambuc #define MEG 1024*1024
62433d6423SLionel Sambuc #define MAGIC ((signed) 0xb4a3f1c2)
63433d6423SLionel Sambuc 
64433d6423SLionel Sambuc static void destr_a(void *arg);
65433d6423SLionel Sambuc static void destr_b(void *arg);
66433d6423SLionel Sambuc static void *thread_a(void *arg);
67433d6423SLionel Sambuc static void *thread_b(void *arg);
68433d6423SLionel Sambuc static void *thread_c(void *arg);
69433d6423SLionel Sambuc static void *thread_d(void *arg);
70433d6423SLionel Sambuc static void thread_e(void);
71433d6423SLionel Sambuc static void *thread_f(void *arg);
72433d6423SLionel Sambuc static void *thread_g(void *arg);
73433d6423SLionel Sambuc static void *thread_h(void *arg);
74433d6423SLionel Sambuc static void test_scheduling(void);
75433d6423SLionel Sambuc static void test_mutex(void);
76433d6423SLionel Sambuc static void test_condition(void);
77433d6423SLionel Sambuc static void test_attributes(void);
78433d6423SLionel Sambuc static void test_keys(void);
79433d6423SLionel Sambuc static void err(int subtest, int error);
80433d6423SLionel Sambuc 
81433d6423SLionel Sambuc /*===========================================================================*
82433d6423SLionel Sambuc  *				thread_a				     *
83433d6423SLionel Sambuc  *===========================================================================*/
thread_a(void * arg)84433d6423SLionel Sambuc static void *thread_a(void *arg) {
85433d6423SLionel Sambuc   th_a++;
86433d6423SLionel Sambuc   return(NULL);
87433d6423SLionel Sambuc }
88433d6423SLionel Sambuc 
89433d6423SLionel Sambuc 
90433d6423SLionel Sambuc /*===========================================================================*
91433d6423SLionel Sambuc  *				thread_b				     *
92433d6423SLionel Sambuc  *===========================================================================*/
thread_b(void * arg)93433d6423SLionel Sambuc static void *thread_b(void *arg) {
94433d6423SLionel Sambuc   th_b++;
95433d6423SLionel Sambuc   if (mthread_once(&once, thread_e) != 0) err(10, 1);
96433d6423SLionel Sambuc   return(NULL);
97433d6423SLionel Sambuc }
98433d6423SLionel Sambuc 
99433d6423SLionel Sambuc 
100433d6423SLionel Sambuc /*===========================================================================*
101433d6423SLionel Sambuc  *				thread_c				     *
102433d6423SLionel Sambuc  *===========================================================================*/
thread_c(void * arg)103433d6423SLionel Sambuc static void *thread_c(void *arg) {
104433d6423SLionel Sambuc   th_c++;
105433d6423SLionel Sambuc   return(NULL);
106433d6423SLionel Sambuc }
107433d6423SLionel Sambuc 
108433d6423SLionel Sambuc 
109433d6423SLionel Sambuc /*===========================================================================*
110433d6423SLionel Sambuc  *				thread_d				     *
111433d6423SLionel Sambuc  *===========================================================================*/
thread_d(void * arg)112433d6423SLionel Sambuc static void *thread_d(void *arg) {
113433d6423SLionel Sambuc   th_d++;
114433d6423SLionel Sambuc   mthread_exit(NULL); /* Thread wants to stop running */
115433d6423SLionel Sambuc   return(NULL);
116433d6423SLionel Sambuc }
117433d6423SLionel Sambuc 
118433d6423SLionel Sambuc 
119433d6423SLionel Sambuc /*===========================================================================*
120433d6423SLionel Sambuc  *				thread_e				     *
121433d6423SLionel Sambuc  *===========================================================================*/
thread_e(void)122433d6423SLionel Sambuc static void thread_e(void) {
123433d6423SLionel Sambuc   th_e++;
124433d6423SLionel Sambuc }
125433d6423SLionel Sambuc 
126433d6423SLionel Sambuc 
127433d6423SLionel Sambuc /*===========================================================================*
128433d6423SLionel Sambuc  *				thread_f				     *
129433d6423SLionel Sambuc  *===========================================================================*/
thread_f(void * arg)130433d6423SLionel Sambuc static void *thread_f(void *arg) {
131433d6423SLionel Sambuc   if (mthread_mutex_lock(condition_mutex) != 0) err(12, 1);
132433d6423SLionel Sambuc   th_f++;
133433d6423SLionel Sambuc   if (mthread_cond_signal(&condition) != 0) err(12, 2);
134433d6423SLionel Sambuc   if (mthread_mutex_unlock(condition_mutex) != 0) err(12, 3);
135433d6423SLionel Sambuc   return(NULL);
136433d6423SLionel Sambuc }
137433d6423SLionel Sambuc 
138433d6423SLionel Sambuc 
139433d6423SLionel Sambuc /*===========================================================================*
140433d6423SLionel Sambuc  *				thread_g				     *
141433d6423SLionel Sambuc  *===========================================================================*/
thread_g(void * arg)142433d6423SLionel Sambuc static void *thread_g(void *arg) {
143433d6423SLionel Sambuc   char bigarray[MTHREAD_STACK_MIN + 1];
144433d6423SLionel Sambuc   if (mthread_mutex_lock(condition_mutex) != 0) err(13, 1);
145433d6423SLionel Sambuc   memset(bigarray, '\0', MTHREAD_STACK_MIN + 1); /* Actually allocate it */
146433d6423SLionel Sambuc   th_g++;
147433d6423SLionel Sambuc   if (mthread_cond_signal(&condition) != 0) err(13, 2);
148433d6423SLionel Sambuc   if (mthread_mutex_unlock(condition_mutex) != 0) err(13, 3);
149433d6423SLionel Sambuc   return(NULL);
150433d6423SLionel Sambuc }
151433d6423SLionel Sambuc 
152433d6423SLionel Sambuc 
153433d6423SLionel Sambuc /*===========================================================================*
154433d6423SLionel Sambuc  *				thread_h				     *
155433d6423SLionel Sambuc  *===========================================================================*/
thread_h(void * arg)156433d6423SLionel Sambuc static void *thread_h(void *arg) {
157433d6423SLionel Sambuc   char bigarray[2 * MEG];
158433d6423SLionel Sambuc   int reply;
159433d6423SLionel Sambuc   if (mthread_mutex_lock(condition_mutex) != 0) err(14, 1);
160433d6423SLionel Sambuc   memset(bigarray, '\0', 2 * MEG); /* Actually allocate it */
161433d6423SLionel Sambuc   th_h++;
162433d6423SLionel Sambuc   if (mthread_cond_signal(&condition) != 0) err(14, 2);
163433d6423SLionel Sambuc   if (mthread_mutex_unlock(condition_mutex) != 0) err(14, 3);
164433d6423SLionel Sambuc   reply = *((int *) arg);
165433d6423SLionel Sambuc   mthread_exit((void *) reply);
166433d6423SLionel Sambuc   return(NULL);
167433d6423SLionel Sambuc }
168433d6423SLionel Sambuc 
169433d6423SLionel Sambuc 
170433d6423SLionel Sambuc /*===========================================================================*
171433d6423SLionel Sambuc  *				err					     *
172433d6423SLionel Sambuc  *===========================================================================*/
err(int sub,int error)173433d6423SLionel Sambuc static void err(int sub, int error) {
174433d6423SLionel Sambuc   /* As we're running with multiple threads, they might all clobber the
175433d6423SLionel Sambuc    * subtest variable. This wrapper prevents that from happening. */
176433d6423SLionel Sambuc 
177433d6423SLionel Sambuc   subtest = sub;
178433d6423SLionel Sambuc   e(error);
179433d6423SLionel Sambuc }
180433d6423SLionel Sambuc 
181433d6423SLionel Sambuc 
182433d6423SLionel Sambuc /*===========================================================================*
183433d6423SLionel Sambuc  *				test_scheduling				     *
184433d6423SLionel Sambuc  *===========================================================================*/
test_scheduling(void)185433d6423SLionel Sambuc static void test_scheduling(void)
186433d6423SLionel Sambuc {
187433d6423SLionel Sambuc   unsigned int i;
188433d6423SLionel Sambuc   thread_t t[7];
189433d6423SLionel Sambuc 
190433d6423SLionel Sambuc #ifdef MDEBUG
191433d6423SLionel Sambuc   mthread_verify();
192433d6423SLionel Sambuc #endif
193433d6423SLionel Sambuc   th_a = th_b = th_c = th_d = th_e = 0;
194433d6423SLionel Sambuc 
195433d6423SLionel Sambuc   if (mthread_create(&t[0], NULL, thread_a, NULL) != 0) err(1, 1);
196433d6423SLionel Sambuc   if (mthread_create(&t[1], NULL, thread_a, NULL) != 0) err(1, 2);
197433d6423SLionel Sambuc   if (mthread_create(&t[2], NULL, thread_a, NULL) != 0) err(1, 3);
198433d6423SLionel Sambuc   if (mthread_create(&t[3], NULL, thread_d, NULL) != 0) err(1, 4);
199433d6423SLionel Sambuc   if (mthread_once(&once, thread_e) != 0) err(1, 5);
200433d6423SLionel Sambuc 
201433d6423SLionel Sambuc   mthread_yield();
202433d6423SLionel Sambuc 
203433d6423SLionel Sambuc   if (mthread_create(&t[4], NULL, thread_c, NULL) != 0) err(1, 6);
204433d6423SLionel Sambuc   mthread_yield();
205433d6423SLionel Sambuc   if (mthread_create(&t[5], NULL, thread_b, NULL) != 0) err(1, 7);
206433d6423SLionel Sambuc   if (mthread_create(&t[6], NULL, thread_a, NULL) != 0) err(1, 8);
207433d6423SLionel Sambuc   mthread_yield();
208433d6423SLionel Sambuc   mthread_yield();
209433d6423SLionel Sambuc   if (mthread_once(&once, thread_e) != 0) err(1, 9);
210433d6423SLionel Sambuc   if (mthread_once(&once, thread_e) != 0) err(1, 10);
211433d6423SLionel Sambuc 
212433d6423SLionel Sambuc   if (th_a != 4) err(1, 11);
213433d6423SLionel Sambuc   if (th_b != 1) err(1, 12);
214433d6423SLionel Sambuc   if (th_c != 1) err(1, 13);
215433d6423SLionel Sambuc   if (th_d != 1) err(1, 14);
216433d6423SLionel Sambuc   if (th_e != 1) err(1, 15);
217433d6423SLionel Sambuc 
218433d6423SLionel Sambuc   for (i = 0; i < (sizeof(t) / sizeof(thread_t)); i++) {
219433d6423SLionel Sambuc 	if (mthread_join(t[i], NULL) != 0) err(1, 16);
220433d6423SLionel Sambuc 	if (mthread_join(t[i], NULL) == 0) err(1, 17); /*Shouldn't work twice*/
221433d6423SLionel Sambuc   }
222433d6423SLionel Sambuc 
223433d6423SLionel Sambuc #ifdef MDEBUG
224433d6423SLionel Sambuc   mthread_verify();
225433d6423SLionel Sambuc #endif
226433d6423SLionel Sambuc   if (mthread_create(NULL, NULL, NULL, NULL) == 0) err(1, 18);
227433d6423SLionel Sambuc   mthread_yield();
228433d6423SLionel Sambuc 
229433d6423SLionel Sambuc #ifdef MDEBUG
230433d6423SLionel Sambuc   mthread_verify();
231433d6423SLionel Sambuc #endif
232433d6423SLionel Sambuc   if (mthread_create(&t[6], NULL, NULL, NULL) == 0) err(1, 19);
233433d6423SLionel Sambuc   mthread_yield();
234433d6423SLionel Sambuc #ifdef MDEBUG
235433d6423SLionel Sambuc   mthread_verify();
236433d6423SLionel Sambuc #endif
237433d6423SLionel Sambuc   if (mthread_join(0xc0ffee, NULL) == 0) err(1, 20);
238433d6423SLionel Sambuc   mthread_yield();
239433d6423SLionel Sambuc   mthread_yield();
240433d6423SLionel Sambuc 
241433d6423SLionel Sambuc #ifdef MDEBUG
242433d6423SLionel Sambuc   mthread_verify();
243433d6423SLionel Sambuc #endif
244433d6423SLionel Sambuc }
245433d6423SLionel Sambuc 
246433d6423SLionel Sambuc 
247433d6423SLionel Sambuc /*===========================================================================*
248433d6423SLionel Sambuc  *				mutex_a					     *
249433d6423SLionel Sambuc  *===========================================================================*/
mutex_a(void * arg)250433d6423SLionel Sambuc static void *mutex_a(void *arg)
251433d6423SLionel Sambuc {
252433d6423SLionel Sambuc   mutex_t *mu = (mutex_t *) arg;
253433d6423SLionel Sambuc 
254433d6423SLionel Sambuc   VERIFY_MUTEX(0, 0, 0, 3, 1);
255433d6423SLionel Sambuc   if (mthread_mutex_lock(&mu[0]) != 0) err(3, 2);
256433d6423SLionel Sambuc 
257433d6423SLionel Sambuc   /* Trying to acquire lock again should fail with EDEADLK */
258433d6423SLionel Sambuc   if (mthread_mutex_lock(&mu[0]) != EDEADLK) err(3, 2);
259433d6423SLionel Sambuc 
260433d6423SLionel Sambuc #ifdef MTHREAD_STRICT
261433d6423SLionel Sambuc   /* Try to acquire lock on uninitialized mutex; should fail with EINVAL */
262433d6423SLionel Sambuc   /* Note: this check only works when libmthread is compiled with
263433d6423SLionel Sambuc    * MTHREAD_STRICT turned on. In POSIX this situation is a MAY fail if... */
264433d6423SLionel Sambuc   if (mthread_mutex_lock(&mu2) != EINVAL) {
265433d6423SLionel Sambuc   	err(3, 4);
266433d6423SLionel Sambuc   	mthread_mutex_unlock(&mu2);
267433d6423SLionel Sambuc   }
268433d6423SLionel Sambuc 
269433d6423SLionel Sambuc   if (mthread_mutex_trylock(&mu2) != EINVAL) {
270433d6423SLionel Sambuc   	err(3, 6);
271433d6423SLionel Sambuc   	mthread_mutex_unlock(&mu2);
272433d6423SLionel Sambuc   }
273433d6423SLionel Sambuc #endif
274433d6423SLionel Sambuc 
275433d6423SLionel Sambuc   if (mthread_mutex_trylock(&mu[1]) != 0) err(3, 8);
276433d6423SLionel Sambuc   mutex_a_step = 1;
277433d6423SLionel Sambuc   mthread_yield();
278433d6423SLionel Sambuc   VERIFY_MUTEX(1, 0, 0, 3, 9);
279433d6423SLionel Sambuc   if (mthread_mutex_trylock(&mu[2]) != EBUSY) err(3, 10);
280433d6423SLionel Sambuc   if (mthread_mutex_lock(&mu[2]) != 0) err(3, 12); /* Transfer control to main
281433d6423SLionel Sambuc   						    * loop.
282433d6423SLionel Sambuc   						    */
283433d6423SLionel Sambuc   VERIFY_MUTEX(1, 0, 0, 3, 13);
284433d6423SLionel Sambuc 
285433d6423SLionel Sambuc   if (mthread_mutex_unlock(&mu[0]) != 0) err(3, 14);
286433d6423SLionel Sambuc   mutex_a_step = 2;
287433d6423SLionel Sambuc   mthread_yield();
288433d6423SLionel Sambuc 
289433d6423SLionel Sambuc   VERIFY_MUTEX(2, 1, 0, 3, 15);
290433d6423SLionel Sambuc   if (mthread_mutex_unlock(&mu[1]) != 0) err(3, 16);
291433d6423SLionel Sambuc   mutex_a_step = 3;
292433d6423SLionel Sambuc 
293433d6423SLionel Sambuc   /* Try with faulty memory locations */
294433d6423SLionel Sambuc   if (mthread_mutex_lock(NULL) == 0) err(3, 17);
295433d6423SLionel Sambuc   if (mthread_mutex_trylock(NULL) == 0) err(3, 18);
296433d6423SLionel Sambuc   if (mthread_mutex_unlock(NULL) == 0) err(3, 19);
297433d6423SLionel Sambuc 
298433d6423SLionel Sambuc   if (mthread_mutex_unlock(&mu[2]) != 0) err(3, 20);
299433d6423SLionel Sambuc   return(NULL);
300433d6423SLionel Sambuc }
301433d6423SLionel Sambuc 
302433d6423SLionel Sambuc 
303433d6423SLionel Sambuc /*===========================================================================*
304433d6423SLionel Sambuc  *				mutex_b					     *
305433d6423SLionel Sambuc  *===========================================================================*/
mutex_b(void * arg)306433d6423SLionel Sambuc static void *mutex_b(void *arg)
307433d6423SLionel Sambuc {
308433d6423SLionel Sambuc   mutex_t *mu = (mutex_t *) arg;
309433d6423SLionel Sambuc 
310433d6423SLionel Sambuc   /* At this point mutex_a thread should have acquired a lock on mu[0]. We
311433d6423SLionel Sambuc    * should not be able to unlock it on behalf of that thread.
312433d6423SLionel Sambuc    */
313433d6423SLionel Sambuc 
314433d6423SLionel Sambuc   VERIFY_MUTEX(1, 0, 0, 4, 1);
315433d6423SLionel Sambuc   if (mthread_mutex_unlock(&mu[0]) != EPERM) err(4, 2);
316433d6423SLionel Sambuc 
317433d6423SLionel Sambuc   /* Probing mu[0] to lock it should tell us it's locked */
318433d6423SLionel Sambuc   if (mthread_mutex_trylock(&mu[0]) != EBUSY) err(4, 4);
319433d6423SLionel Sambuc 
320433d6423SLionel Sambuc   if (mthread_mutex_lock(&mu[0]) != 0) err(4, 5);
321433d6423SLionel Sambuc   mutex_b_step = 1;
322433d6423SLionel Sambuc   VERIFY_MUTEX(2, 1, 0, 4, 6);
323433d6423SLionel Sambuc   if (mthread_mutex_lock(&mu[1]) != 0) err(4, 6);
324433d6423SLionel Sambuc   mutex_b_step = 2;
325433d6423SLionel Sambuc   VERIFY_MUTEX(3, 2, 2, 4, 7);
326433d6423SLionel Sambuc   mthread_yield();
327433d6423SLionel Sambuc   VERIFY_MUTEX(3, 2, 2, 4, 8);
328433d6423SLionel Sambuc 
329433d6423SLionel Sambuc   if (mthread_mutex_unlock(&mu[0]) != 0) err(4, 7);
330433d6423SLionel Sambuc   mutex_b_step = 3;
331433d6423SLionel Sambuc   mthread_yield();
332433d6423SLionel Sambuc 
333433d6423SLionel Sambuc   if (mthread_mutex_unlock(&mu[1]) != 0) err(4, 8);
334433d6423SLionel Sambuc   mutex_b_step = 4;
335433d6423SLionel Sambuc   return(NULL);
336433d6423SLionel Sambuc }
337433d6423SLionel Sambuc 
338433d6423SLionel Sambuc 
339433d6423SLionel Sambuc /*===========================================================================*
340433d6423SLionel Sambuc  *				mutex_c					     *
341433d6423SLionel Sambuc  *===========================================================================*/
mutex_c(void * arg)342433d6423SLionel Sambuc static void *mutex_c(void *arg)
343433d6423SLionel Sambuc {
344433d6423SLionel Sambuc   mutex_t *mu = (mutex_t *) arg;
345433d6423SLionel Sambuc 
346433d6423SLionel Sambuc   VERIFY_MUTEX(1, 0, 0, 5, 1);
347433d6423SLionel Sambuc   if (mthread_mutex_lock(&mu[1]) != 0) err(5, 2);
348433d6423SLionel Sambuc   mutex_c_step = 1;
349433d6423SLionel Sambuc   VERIFY_MUTEX(3, 1, 1, 5, 3);
350433d6423SLionel Sambuc   mthread_yield();
351433d6423SLionel Sambuc   VERIFY_MUTEX(3, 1, 1, 5, 4);
352433d6423SLionel Sambuc 
353433d6423SLionel Sambuc   if (mthread_mutex_unlock(&mu[1]) != 0) err(5, 5);
354433d6423SLionel Sambuc   mutex_c_step = 2;
355433d6423SLionel Sambuc   if (mthread_mutex_lock(&mu[0]) != 0) err(5, 6);
356433d6423SLionel Sambuc   mutex_c_step = 3;
357433d6423SLionel Sambuc   VERIFY_MUTEX(3, 3, 3, 5, 7);
358433d6423SLionel Sambuc   mthread_yield();
359433d6423SLionel Sambuc   VERIFY_MUTEX(3, 4, 3, 5, 8);
360433d6423SLionel Sambuc 
361433d6423SLionel Sambuc   if (mthread_mutex_unlock(&mu[0]) != 0) err(5, 9);
362433d6423SLionel Sambuc   mutex_c_step = 4;
363433d6423SLionel Sambuc   return(NULL);
364433d6423SLionel Sambuc }
365433d6423SLionel Sambuc 
366433d6423SLionel Sambuc 
367433d6423SLionel Sambuc /*===========================================================================*
368433d6423SLionel Sambuc  *				test_mutex				     *
369433d6423SLionel Sambuc  *===========================================================================*/
test_mutex(void)370433d6423SLionel Sambuc static void test_mutex(void)
371433d6423SLionel Sambuc {
372433d6423SLionel Sambuc   unsigned int i;
373433d6423SLionel Sambuc   thread_t t[3];
374433d6423SLionel Sambuc #ifdef MDEBUG
375433d6423SLionel Sambuc   mthread_verify();
376433d6423SLionel Sambuc #endif
377433d6423SLionel Sambuc   if (mthread_mutex_init(&mu[0], NULL) != 0) err(2, 1);
378433d6423SLionel Sambuc   if (mthread_mutex_init(&mu[1], NULL) != 0) err(2, 2);
379433d6423SLionel Sambuc   if (mthread_mutex_init(&mu[2], NULL) != 0) err(2, 3);
380433d6423SLionel Sambuc 
381433d6423SLionel Sambuc   if (mthread_create(&t[0], NULL, mutex_a, (void *) mu) != 0) err(2, 3);
382433d6423SLionel Sambuc   if (mthread_create(&t[1], NULL, mutex_b, (void *) mu) != 0) err(2, 4);
383433d6423SLionel Sambuc   if (mthread_create(&t[2], NULL, mutex_c, (void *) mu) != 0) err(2, 5);
384433d6423SLionel Sambuc 
385433d6423SLionel Sambuc   if (mthread_mutex_lock(&mu[2]) != 0) err(2, 6);
386433d6423SLionel Sambuc 
387433d6423SLionel Sambuc   mthread_yield_all(); /* Should result in a RUNNABLE mutex_a, and a blocked
388433d6423SLionel Sambuc   			* on mutex mutex_b and mutex_c.
389433d6423SLionel Sambuc   			*/
390433d6423SLionel Sambuc 
391433d6423SLionel Sambuc   VERIFY_MUTEX(1, 0, 0, 2, 7); /* err(2, 7) */
392433d6423SLionel Sambuc   if (mthread_mutex_unlock(&mu[2]) != 0) err(2, 8);
393433d6423SLionel Sambuc 
394433d6423SLionel Sambuc   mthread_yield();	/* Should schedule mutex_a to release the lock on the
395433d6423SLionel Sambuc 			 * mu[0] mutex. Consequently allowing mutex_b and mutex_c
396433d6423SLionel Sambuc   			* to acquire locks on the mutexes and exit.
397433d6423SLionel Sambuc   			*/
398433d6423SLionel Sambuc   VERIFY_MUTEX(2, 0, 0, 2, 9);
399433d6423SLionel Sambuc 
400433d6423SLionel Sambuc   for (i = 0; i < (sizeof(t) / sizeof(thread_t)); i++)
401433d6423SLionel Sambuc 	if (mthread_join(t[i], NULL) != 0) err(2, 10);
402433d6423SLionel Sambuc 
403433d6423SLionel Sambuc   if (mthread_mutex_destroy(&mu[0]) != 0) err(2, 11);
404433d6423SLionel Sambuc   if (mthread_mutex_destroy(&mu[1]) != 0) err(2, 12);
405433d6423SLionel Sambuc   if (mthread_mutex_destroy(&mu[2]) != 0) err(2, 13);
406433d6423SLionel Sambuc 
407433d6423SLionel Sambuc #ifdef MDEBUG
408433d6423SLionel Sambuc   mthread_verify();
409433d6423SLionel Sambuc #endif
410433d6423SLionel Sambuc }
411433d6423SLionel Sambuc 
412433d6423SLionel Sambuc 
413433d6423SLionel Sambuc /*===========================================================================*
414433d6423SLionel Sambuc  *					cond_a				     *
415433d6423SLionel Sambuc  *===========================================================================*/
cond_a(void * arg)416433d6423SLionel Sambuc static void *cond_a(void *arg)
417433d6423SLionel Sambuc {
418433d6423SLionel Sambuc   cond_t c;
419433d6423SLionel Sambuc   int did_count = 0;
420433d6423SLionel Sambuc   while(1) {
421433d6423SLionel Sambuc   	if (mthread_mutex_lock(condition_mutex) != 0) err(6, 1);
422433d6423SLionel Sambuc   	while (count >= THRESH1 && count <= THRESH2) {
423433d6423SLionel Sambuc   		if (mthread_cond_wait(&condition, condition_mutex) != 0)
424433d6423SLionel Sambuc   			err(6, 2);
425433d6423SLionel Sambuc   	}
426433d6423SLionel Sambuc   	if (mthread_mutex_unlock(condition_mutex) != 0) err(6, 3);
427433d6423SLionel Sambuc 
428433d6423SLionel Sambuc 	mthread_yield();
429433d6423SLionel Sambuc 
430433d6423SLionel Sambuc   	if (mthread_mutex_lock(count_mutex) != 0) err(6, 4);
431433d6423SLionel Sambuc   	count++;
432433d6423SLionel Sambuc   	did_count++;
433433d6423SLionel Sambuc   	if (mthread_mutex_unlock(count_mutex) != 0) err(6, 5);
434433d6423SLionel Sambuc 
435433d6423SLionel Sambuc   	if (count >= ROUNDS) break;
436433d6423SLionel Sambuc   }
437433d6423SLionel Sambuc   if (!(did_count <= count - (THRESH2 - THRESH1 + 1))) err(6, 6);
438433d6423SLionel Sambuc 
439433d6423SLionel Sambuc   /* Try faulty addresses */
440433d6423SLionel Sambuc   if (mthread_mutex_lock(condition_mutex) != 0) err(6, 7);
441433d6423SLionel Sambuc #ifdef MTHREAD_STRICT
442433d6423SLionel Sambuc   /* Condition c is not initialized, so whatever we do with it should fail. */
443433d6423SLionel Sambuc   if (mthread_cond_wait(&c, condition_mutex) == 0) err(6, 8);
444433d6423SLionel Sambuc   if (mthread_cond_wait(NULL, condition_mutex) == 0) err(6, 9);
445433d6423SLionel Sambuc   if (mthread_cond_signal(&c) == 0) err(6, 10);
446433d6423SLionel Sambuc   if (mthread_mutex_unlock(condition_mutex) != 0) err(6, 11);
447433d6423SLionel Sambuc 
448433d6423SLionel Sambuc   /* Try again with an unlocked mutex */
449433d6423SLionel Sambuc   if (mthread_cond_wait(&c, condition_mutex) == 0) err(6, 12);
450433d6423SLionel Sambuc   if (mthread_cond_signal(&c) == 0) err(6, 13);
451433d6423SLionel Sambuc #endif
452433d6423SLionel Sambuc 
453433d6423SLionel Sambuc   /* And again with an unlocked mutex, but initialized c */
454433d6423SLionel Sambuc   if (mthread_cond_init(&c, NULL) != 0) err(6, 14);
455433d6423SLionel Sambuc   if (mthread_cond_wait(&c, condition_mutex) == 0) err(6, 15);
456433d6423SLionel Sambuc   if (mthread_cond_signal(&c) != 0) err(6, 16);/*c.f., 6.10 this should work!*/
457433d6423SLionel Sambuc   if (mthread_cond_destroy(&c) != 0) err(6, 17);
458433d6423SLionel Sambuc   return(NULL);
459433d6423SLionel Sambuc }
460433d6423SLionel Sambuc 
461433d6423SLionel Sambuc 
462433d6423SLionel Sambuc /*===========================================================================*
463433d6423SLionel Sambuc  *					cond_b				     *
464433d6423SLionel Sambuc  *===========================================================================*/
cond_b(void * arg)465433d6423SLionel Sambuc static void *cond_b(void *arg)
466433d6423SLionel Sambuc {
467433d6423SLionel Sambuc   int did_count = 0;
468433d6423SLionel Sambuc   while(1) {
469433d6423SLionel Sambuc   	if (mthread_mutex_lock(condition_mutex) != 0) err(7, 1);
470433d6423SLionel Sambuc   	if (count < THRESH1 || count > THRESH2)
471433d6423SLionel Sambuc   		if (mthread_cond_signal(&condition) != 0) err(7, 2);
472433d6423SLionel Sambuc   	if (mthread_mutex_unlock(condition_mutex) != 0) err(7, 3);
473433d6423SLionel Sambuc 
474433d6423SLionel Sambuc 	mthread_yield();
475433d6423SLionel Sambuc 
476433d6423SLionel Sambuc   	if (mthread_mutex_lock(count_mutex) != 0) err(7, 4);
477433d6423SLionel Sambuc   	count++;
478433d6423SLionel Sambuc   	did_count++;
479433d6423SLionel Sambuc   	if (mthread_mutex_unlock(count_mutex) != 0) err(7, 5);
480433d6423SLionel Sambuc 
481433d6423SLionel Sambuc   	if (count >= ROUNDS) break;
482433d6423SLionel Sambuc   }
483433d6423SLionel Sambuc 
484433d6423SLionel Sambuc   if (!(did_count >= count - (THRESH2 - THRESH1 + 1))) err(7, 6);
485433d6423SLionel Sambuc 
486433d6423SLionel Sambuc   return(NULL);
487433d6423SLionel Sambuc }
488433d6423SLionel Sambuc 
489433d6423SLionel Sambuc /*===========================================================================*
490433d6423SLionel Sambuc  *				cond_broadcast				     *
491433d6423SLionel Sambuc  *===========================================================================*/
cond_broadcast(void * arg)492433d6423SLionel Sambuc static void *cond_broadcast(void *arg)
493433d6423SLionel Sambuc {
494433d6423SLionel Sambuc   if (mthread_mutex_lock(condition_mutex) != 0) err(9, 1);
495433d6423SLionel Sambuc 
496433d6423SLionel Sambuc   while(!condition_met)
497433d6423SLionel Sambuc   	if (mthread_cond_wait(&condition, condition_mutex) != 0) err(9, 2);
498433d6423SLionel Sambuc 
499433d6423SLionel Sambuc   if (mthread_mutex_unlock(condition_mutex) != 0) err(9, 3);
500433d6423SLionel Sambuc 
501433d6423SLionel Sambuc   if (mthread_mutex_lock(count_mutex) != 0) err(9, 4);
502433d6423SLionel Sambuc   count++;
503433d6423SLionel Sambuc   if (mthread_mutex_unlock(count_mutex) != 0) err(9, 5);
504433d6423SLionel Sambuc   return(NULL);
505433d6423SLionel Sambuc }
506433d6423SLionel Sambuc 
507433d6423SLionel Sambuc /*===========================================================================*
508433d6423SLionel Sambuc  *				test_condition				     *
509433d6423SLionel Sambuc  *===========================================================================*/
test_condition(void)510433d6423SLionel Sambuc static void test_condition(void)
511433d6423SLionel Sambuc {
512433d6423SLionel Sambuc #define NTHREADS 10
513433d6423SLionel Sambuc   int i;
514433d6423SLionel Sambuc   thread_t t[2], s[NTHREADS];
515433d6423SLionel Sambuc   count_mutex = &mu[0];
516433d6423SLionel Sambuc   condition_mutex = &mu[1];
517433d6423SLionel Sambuc 
518433d6423SLionel Sambuc   /* Test simple condition variable behavior: Two threads increase a counter.
519433d6423SLionel Sambuc    * At some point one thread waits for a condition and the other thread
520433d6423SLionel Sambuc    * signals the condition. Consequently, one thread increased the counter a
521433d6423SLionel Sambuc    * few times less than other thread. Although the difference is 'random',
522433d6423SLionel Sambuc    * there is a guaranteed minimum difference that we can measure.
523433d6423SLionel Sambuc    */
524433d6423SLionel Sambuc 
525433d6423SLionel Sambuc #ifdef MDEBUG
526433d6423SLionel Sambuc   mthread_verify();
527433d6423SLionel Sambuc #endif
528433d6423SLionel Sambuc 
529433d6423SLionel Sambuc   if (mthread_mutex_init(count_mutex, NULL) != 0) err(8, 1);
530433d6423SLionel Sambuc   if (mthread_mutex_init(condition_mutex, NULL) != 0) err(8, 2);
531433d6423SLionel Sambuc   if (mthread_cond_init(&condition, NULL) != 0) err(8, 3);
532433d6423SLionel Sambuc   count = 0;
533433d6423SLionel Sambuc 
534433d6423SLionel Sambuc   if (mthread_create(&t[0], NULL, cond_a, NULL) != 0) err(8, 4);
535433d6423SLionel Sambuc   if (mthread_create(&t[1], NULL, cond_b, NULL) != 0) err(8, 5);
536433d6423SLionel Sambuc 
537433d6423SLionel Sambuc   for (i = 0; i < (sizeof(t) / sizeof(thread_t)); i++)
538433d6423SLionel Sambuc 	if (mthread_join(t[i], NULL) != 0) err(8, 6);
539433d6423SLionel Sambuc 
540433d6423SLionel Sambuc   if (mthread_mutex_destroy(count_mutex) != 0) err(8, 7);
541433d6423SLionel Sambuc   if (mthread_mutex_destroy(condition_mutex) != 0) err(8, 8);
542433d6423SLionel Sambuc   if (mthread_cond_destroy(&condition) != 0) err(8, 9);
543433d6423SLionel Sambuc 
544433d6423SLionel Sambuc #ifdef MTHREAD_STRICT
545433d6423SLionel Sambuc   /* Let's try to destroy it again. Should fails as it's uninitialized. */
546433d6423SLionel Sambuc   /* Note: this only works when libmthread is compiled with MTHREAD_STRICT. In
547433d6423SLionel Sambuc    * POSIX this situation is a MAY fail if... */
548433d6423SLionel Sambuc   if (mthread_cond_destroy(&condition) == 0) err(8, 10);
549433d6423SLionel Sambuc #endif
550433d6423SLionel Sambuc 
551433d6423SLionel Sambuc #ifdef MDEBUG
552433d6423SLionel Sambuc   mthread_verify();
553433d6423SLionel Sambuc #endif
554433d6423SLionel Sambuc 
555433d6423SLionel Sambuc   /* Test signal broadcasting: spawn N threads that will increase a counter
556433d6423SLionel Sambuc    * after a condition has been signaled. The counter must equal N. */
557433d6423SLionel Sambuc   if (mthread_mutex_init(count_mutex, NULL) != 0) err(8, 11);
558433d6423SLionel Sambuc   if (mthread_mutex_init(condition_mutex, NULL) != 0) err(8, 12);
559433d6423SLionel Sambuc   if (mthread_cond_init(&condition, NULL) != 0) err(8, 13);
560433d6423SLionel Sambuc   condition_met = count = 0;
561433d6423SLionel Sambuc 
562433d6423SLionel Sambuc   for (i = 0; i < NTHREADS; i++)
563433d6423SLionel Sambuc 	if (mthread_create(&s[i], NULL, cond_broadcast, NULL) != 0) err(8, 14);
564433d6423SLionel Sambuc 
565433d6423SLionel Sambuc   /* Allow other threads to block on the condition variable. If we don't yield,
566433d6423SLionel Sambuc    * the threads will only start running when we call mthread_join below. In
567433d6423SLionel Sambuc    * that case the while loop in cond_broadcast will never evaluate to true.
568433d6423SLionel Sambuc    */
569433d6423SLionel Sambuc   mthread_yield();
570433d6423SLionel Sambuc 
571433d6423SLionel Sambuc   if (mthread_mutex_lock(condition_mutex) != 0) err(8, 15);
572433d6423SLionel Sambuc   condition_met = 1;
573433d6423SLionel Sambuc   if (mthread_cond_broadcast(&condition) != 0) err(8, 16);
574433d6423SLionel Sambuc   if (mthread_mutex_unlock(condition_mutex) != 0) err(8, 17);
575433d6423SLionel Sambuc 
576433d6423SLionel Sambuc   for (i = 0; i < (sizeof(s) / sizeof(thread_t)); i++)
577433d6423SLionel Sambuc 	if (mthread_join(s[i], NULL) != 0) err(8, 18);
578433d6423SLionel Sambuc 
579433d6423SLionel Sambuc   if (count != NTHREADS) err(8, 19);
580433d6423SLionel Sambuc   if (mthread_mutex_destroy(count_mutex) != 0) err(8, 20);
581433d6423SLionel Sambuc   if (mthread_mutex_destroy(condition_mutex) != 0) err(8, 21);
582433d6423SLionel Sambuc   if (mthread_cond_destroy(&condition) != 0) err(8, 22);
583433d6423SLionel Sambuc 
584433d6423SLionel Sambuc #ifdef MTHREAD_STRICT
585433d6423SLionel Sambuc   /* Again, destroying the condition variable twice shouldn't work */
586433d6423SLionel Sambuc   /* See previous note about MTHREAD_STRICT */
587433d6423SLionel Sambuc   if (mthread_cond_destroy(&condition) == 0) err(8, 23);
588433d6423SLionel Sambuc #endif
589433d6423SLionel Sambuc 
590433d6423SLionel Sambuc #ifdef MDEBUG
591433d6423SLionel Sambuc   mthread_verify();
592433d6423SLionel Sambuc #endif
593433d6423SLionel Sambuc }
594433d6423SLionel Sambuc 
595433d6423SLionel Sambuc /*===========================================================================*
596433d6423SLionel Sambuc  *				test_attributes				     *
597433d6423SLionel Sambuc  *===========================================================================*/
test_attributes(void)598433d6423SLionel Sambuc static void test_attributes(void)
599433d6423SLionel Sambuc {
600433d6423SLionel Sambuc   attr_t tattr;
601433d6423SLionel Sambuc   thread_t tid;
602*d26b52b7SDavid van Moolenbroek   int detachstate = -1;
603433d6423SLionel Sambuc   unsigned int i, no_ints, stack_untouched = 1;
604*d26b52b7SDavid van Moolenbroek   void *status, *stackaddr, *newstackaddr;
605433d6423SLionel Sambuc   int *stackp;
606433d6423SLionel Sambuc   size_t stacksize, newstacksize;
607433d6423SLionel Sambuc 
608433d6423SLionel Sambuc #ifdef MDEBUG
609433d6423SLionel Sambuc   mthread_verify();
610433d6423SLionel Sambuc #endif
611433d6423SLionel Sambuc 
612433d6423SLionel Sambuc   /* Initialize thread attribute and try to read the default values */
613433d6423SLionel Sambuc   if (mthread_attr_init(&tattr) != 0) err(11, 1);
614433d6423SLionel Sambuc   if (mthread_attr_getdetachstate(&tattr, &detachstate) != 0) err(11, 2);
615433d6423SLionel Sambuc   if (detachstate != MTHREAD_CREATE_JOINABLE) err(11, 3);
616433d6423SLionel Sambuc   if (mthread_attr_getstack(&tattr, &stackaddr, &stacksize) != 0) err(11, 4);
617433d6423SLionel Sambuc   if (stackaddr != NULL) err(11, 5);
618433d6423SLionel Sambuc   if (stacksize != (size_t) 0) err(11, 6);
619433d6423SLionel Sambuc 
620433d6423SLionel Sambuc   /* Modify the attribute ... */
621433d6423SLionel Sambuc   /* Try bogus detach state value */
622433d6423SLionel Sambuc   if (mthread_attr_setdetachstate(&tattr, 0xc0ffee) == 0) err(11, 7);
623433d6423SLionel Sambuc   if (mthread_attr_setdetachstate(&tattr, MTHREAD_CREATE_DETACHED) != 0)
624433d6423SLionel Sambuc   	err(11, 8);
625433d6423SLionel Sambuc   newstacksize = (size_t) MEG;
626433d6423SLionel Sambuc   if ((newstackaddr = malloc(newstacksize)) == NULL) err(11, 9);
627433d6423SLionel Sambuc   if (mthread_attr_setstack(&tattr, newstackaddr, newstacksize) != 0)
628433d6423SLionel Sambuc   	err(11, 10);
629433d6423SLionel Sambuc    /* ... and read back the new values. */
630433d6423SLionel Sambuc   if (mthread_attr_getdetachstate(&tattr, &detachstate) != 0) err(11, 11);
631433d6423SLionel Sambuc   if (detachstate != MTHREAD_CREATE_DETACHED) err(11, 12);
632433d6423SLionel Sambuc   if (mthread_attr_getstack(&tattr, &stackaddr, &stacksize) != 0) err(11, 13);
633433d6423SLionel Sambuc   if (stackaddr != newstackaddr) err(11, 14);
634433d6423SLionel Sambuc   if (stacksize != newstacksize) err(11, 15);
635433d6423SLionel Sambuc   if (mthread_attr_destroy(&tattr) != 0) err(11, 16);
636433d6423SLionel Sambuc   free(newstackaddr);
637433d6423SLionel Sambuc 
638433d6423SLionel Sambuc   /* Try to allocate too small a stack; it should fail and the attribute
639433d6423SLionel Sambuc    * values should remain as is.
640433d6423SLionel Sambuc    */
641433d6423SLionel Sambuc   newstacksize = MTHREAD_STACK_MIN - 1;
642433d6423SLionel Sambuc   stackaddr = NULL;
643433d6423SLionel Sambuc   stacksize = 0;
644433d6423SLionel Sambuc   if (mthread_attr_init(&tattr) != 0) err(11, 17);
645433d6423SLionel Sambuc   if ((newstackaddr = malloc(newstacksize)) == NULL) err(11, 18);
646433d6423SLionel Sambuc   if (mthread_attr_setstack(&tattr, newstackaddr, newstacksize) != EINVAL)
647433d6423SLionel Sambuc   	err(11, 19);
648433d6423SLionel Sambuc   if (mthread_attr_getstack(&tattr, &stackaddr, &stacksize) != 0) err(11, 21);
649433d6423SLionel Sambuc   if (stackaddr == newstackaddr) err(11, 22);
650433d6423SLionel Sambuc   if (stacksize == newstacksize) err(11, 23);
651433d6423SLionel Sambuc   if (mthread_attr_destroy(&tattr) != 0) err(11, 24);
652433d6423SLionel Sambuc   free(newstackaddr);
653433d6423SLionel Sambuc 
654433d6423SLionel Sambuc   /* Tell attribute to let the system allocate a stack for the thread and only
655433d6423SLionel Sambuc    * dictate how big that stack should be (2 megabyte, not actually allocated
656433d6423SLionel Sambuc    * yet).
657433d6423SLionel Sambuc    */
658433d6423SLionel Sambuc   if (mthread_attr_init(&tattr) != 0) err(11, 25);
659433d6423SLionel Sambuc   if (mthread_attr_setstack(&tattr, NULL /* System allocated */, 2*MEG) != 0)
660433d6423SLionel Sambuc   	err(11, 26);
661433d6423SLionel Sambuc   if (mthread_attr_getstack(&tattr, &stackaddr, &stacksize) != 0) err(11, 27);
662433d6423SLionel Sambuc   if (stackaddr != NULL) err(11, 28);
663433d6423SLionel Sambuc   if (stacksize != 2*MEG) err(11, 29);
664433d6423SLionel Sambuc 
665433d6423SLionel Sambuc   /* Use set/getstacksize to set and retrieve new stack sizes */
666433d6423SLionel Sambuc   stacksize = 0;
667433d6423SLionel Sambuc   if (mthread_attr_getstacksize(&tattr, &stacksize) != 0) err(11, 30);
668433d6423SLionel Sambuc   if (stacksize != 2*MEG) err(11, 31);
669433d6423SLionel Sambuc   newstacksize = MEG;
670433d6423SLionel Sambuc   if (mthread_attr_setstacksize(&tattr, newstacksize) != 0) err(11, 32);
671433d6423SLionel Sambuc   if (mthread_attr_getstacksize(&tattr, &stacksize) != 0) err(11, 33);
672433d6423SLionel Sambuc   if (stacksize != newstacksize) err(11, 34);
673433d6423SLionel Sambuc   if (mthread_attr_destroy(&tattr) != 0) err(11, 35);
674433d6423SLionel Sambuc 
675433d6423SLionel Sambuc   /* Perform same tests, but also actually use them in a thread */
676433d6423SLionel Sambuc   if (mthread_attr_init(&tattr) != 0) err(11, 36);
677433d6423SLionel Sambuc   if (mthread_attr_setdetachstate(&tattr, MTHREAD_CREATE_DETACHED) != 0)
678433d6423SLionel Sambuc   	err(11, 37);
679433d6423SLionel Sambuc   condition_mutex = &mu[0];
680433d6423SLionel Sambuc   if (mthread_mutex_init(condition_mutex, NULL) != 0) err(11, 38);
681433d6423SLionel Sambuc   if (mthread_cond_init(&condition, NULL) != 0) err(11, 39);
682433d6423SLionel Sambuc   if (mthread_mutex_lock(condition_mutex) != 0) err(11, 40);
683433d6423SLionel Sambuc   if (mthread_create(&tid, &tattr, thread_f, NULL) != 0) err(11, 41);
684433d6423SLionel Sambuc   /* Wait for thread_f to finish */
685433d6423SLionel Sambuc   if (mthread_cond_wait(&condition, condition_mutex) != 0) err(11, 42);
686433d6423SLionel Sambuc   if (mthread_mutex_unlock(condition_mutex) != 0) err(11, 43);
687433d6423SLionel Sambuc   if (th_f != 1) err(11, 44);
688433d6423SLionel Sambuc   /* Joining a detached thread should fail */
689433d6423SLionel Sambuc   if (mthread_join(tid, NULL) == 0) err(11, 45);
690433d6423SLionel Sambuc   if (mthread_attr_destroy(&tattr) != 0) err(11, 46);
691433d6423SLionel Sambuc 
692433d6423SLionel Sambuc   /* Try telling the attribute how large the stack should be */
693433d6423SLionel Sambuc   if (mthread_attr_init(&tattr) != 0) err(11, 47);
694433d6423SLionel Sambuc   if (mthread_attr_setstack(&tattr, NULL, 2 * MTHREAD_STACK_MIN) != 0)
695433d6423SLionel Sambuc   	err(11, 48);
696433d6423SLionel Sambuc   if (mthread_mutex_lock(condition_mutex) != 0) err(11, 49);
697433d6423SLionel Sambuc   if (mthread_create(&tid, &tattr, thread_g, NULL) != 0) err(11, 50);
698433d6423SLionel Sambuc   /* Wait for thread_g to finish */
699433d6423SLionel Sambuc   if (mthread_cond_wait(&condition, condition_mutex) != 0) err(11, 51);
700433d6423SLionel Sambuc   if (mthread_mutex_unlock(condition_mutex) != 0) err(11, 52);
701433d6423SLionel Sambuc   if (th_g != 1) err(11, 53);
702433d6423SLionel Sambuc   if (mthread_attr_setdetachstate(&tattr, MTHREAD_CREATE_DETACHED) != 0)
703433d6423SLionel Sambuc   	err(11, 54); /* Shouldn't affect the join below, as thread is already
704433d6423SLionel Sambuc   		      * running as joinable. If this attribute should be
705433d6423SLionel Sambuc   		      * modified after thread creation, use mthread_detach().
706433d6423SLionel Sambuc   		      */
707433d6423SLionel Sambuc   if (mthread_join(tid, NULL) != 0) err(11, 55);
708433d6423SLionel Sambuc   if (mthread_attr_destroy(&tattr) != 0) err(11, 56);
709433d6423SLionel Sambuc 
710433d6423SLionel Sambuc   /* Try telling the attribute how large the stack should be and where it is
711433d6423SLionel Sambuc    * located.
712433d6423SLionel Sambuc    */
713433d6423SLionel Sambuc   if (mthread_attr_init(&tattr) != 0) err(11, 57);
714433d6423SLionel Sambuc   stacksize = 3 * MEG;
715433d6423SLionel Sambuc   /* Make sure this test is meaningful. We have to verify that we actually
716433d6423SLionel Sambuc    * use a custom stack. So we're going to allocate an array on the stack in
717433d6423SLionel Sambuc    * thread_h that should at least be bigger than the default stack size
718433d6423SLionel Sambuc    * allocated by the system.
719433d6423SLionel Sambuc    */
720433d6423SLionel Sambuc   if (2 * MEG <= MTHREAD_STACK_MIN) err(11, 58);
721433d6423SLionel Sambuc   if ((stackaddr = malloc(stacksize)) == NULL) err(11, 59);
722433d6423SLionel Sambuc   /* Fill stack with pattern. We assume that the beginning of the stack
723433d6423SLionel Sambuc    * should be overwritten with something and that the end should remain
724433d6423SLionel Sambuc    * untouched. The thread will zero-fill around two-thirds of the stack with
725433d6423SLionel Sambuc    * zeroes, so we can check if that's true.
726433d6423SLionel Sambuc    */
727433d6423SLionel Sambuc   stackp = stackaddr;
728433d6423SLionel Sambuc   no_ints = stacksize / sizeof(int);
729433d6423SLionel Sambuc   for (i = 0; i < no_ints ; i++)
730433d6423SLionel Sambuc 	stackp[i] = MAGIC;
731433d6423SLionel Sambuc   if (mthread_attr_setstack(&tattr, stackaddr, stacksize) != 0) err(11, 60);
732433d6423SLionel Sambuc   if (mthread_mutex_lock(condition_mutex) != 0) err(11, 61);
733433d6423SLionel Sambuc   if (mthread_create(&tid, &tattr, thread_h, (void *) &stacksize) != 0)
734433d6423SLionel Sambuc   	err(11, 62);
735433d6423SLionel Sambuc   /* Wait for thread h to finish */
736433d6423SLionel Sambuc   if (mthread_cond_wait(&condition, condition_mutex) != 0) err(11, 63);
737433d6423SLionel Sambuc   if (th_h != 1) err(11, 64);
738433d6423SLionel Sambuc   if (mthread_mutex_unlock(condition_mutex) != 0) err(11, 65);
739433d6423SLionel Sambuc 
740433d6423SLionel Sambuc   /* Verify stack hypothesis; we assume a stack is used from the top and grows
741433d6423SLionel Sambuc    * downwards.
742433d6423SLionel Sambuc    */
743433d6423SLionel Sambuc #if defined(__i386__) || defined(__arm__)
744433d6423SLionel Sambuc   if (stackp[0] != MAGIC) err(11, 66); /* End of the stack */
745433d6423SLionel Sambuc   for (i = no_ints - 1 - 16; i < no_ints; i++)
746433d6423SLionel Sambuc   	if (stackp[i] != MAGIC) stack_untouched = 0;
747433d6423SLionel Sambuc   if (stack_untouched) err(11, 67); /* Beginning of the stack */
748433d6423SLionel Sambuc   if (stackp[no_ints / 2] != 0) err(11, 68);/*Zero half way through the stack*/
749433d6423SLionel Sambuc #else
750433d6423SLionel Sambuc #error "Unsupported chip for this test"
751433d6423SLionel Sambuc #endif
752433d6423SLionel Sambuc 
753*d26b52b7SDavid van Moolenbroek   if (mthread_join(tid, &status) != 0) err(11, 69);
754433d6423SLionel Sambuc   if ((size_t) status != stacksize) err(11, 70);
755433d6423SLionel Sambuc   if (mthread_attr_destroy(&tattr) != 0) err(11, 71);
756433d6423SLionel Sambuc   if (mthread_mutex_destroy(condition_mutex) != 0) err(11, 72);
757433d6423SLionel Sambuc   if (mthread_cond_destroy(&condition) != 0) err(11, 73);
758433d6423SLionel Sambuc   free(stackaddr);
759433d6423SLionel Sambuc 
760433d6423SLionel Sambuc #ifdef MDEBUG
761433d6423SLionel Sambuc   mthread_verify();
762433d6423SLionel Sambuc #endif
763433d6423SLionel Sambuc }
764433d6423SLionel Sambuc 
765433d6423SLionel Sambuc /*===========================================================================*
766433d6423SLionel Sambuc  *				destr_a					     *
767433d6423SLionel Sambuc  *===========================================================================*/
destr_a(void * value)768433d6423SLionel Sambuc static void destr_a(void *value)
769433d6423SLionel Sambuc {
770433d6423SLionel Sambuc   int num;
771433d6423SLionel Sambuc 
772433d6423SLionel Sambuc   num = (int) value;
773433d6423SLionel Sambuc 
774433d6423SLionel Sambuc   /* This destructor must be called once for all of the values 1..4. */
775433d6423SLionel Sambuc   if (num <= 0 || num > 4) err(15, 1);
776433d6423SLionel Sambuc 
777433d6423SLionel Sambuc   if (values[num - 1] != 1) err(15, 2);
778433d6423SLionel Sambuc 
779433d6423SLionel Sambuc   values[num - 1] = 2;
780433d6423SLionel Sambuc }
781433d6423SLionel Sambuc 
782433d6423SLionel Sambuc /*===========================================================================*
783433d6423SLionel Sambuc  *				destr_b					     *
784433d6423SLionel Sambuc  *===========================================================================*/
destr_b(void * value)785433d6423SLionel Sambuc static void destr_b(void *value)
786433d6423SLionel Sambuc {
787433d6423SLionel Sambuc   /* This destructor must never trigger. */
788433d6423SLionel Sambuc   err(16, 1);
789433d6423SLionel Sambuc }
790433d6423SLionel Sambuc 
791433d6423SLionel Sambuc /*===========================================================================*
792433d6423SLionel Sambuc  *				key_a					     *
793433d6423SLionel Sambuc  *===========================================================================*/
key_a(void * arg)794433d6423SLionel Sambuc static void *key_a(void *arg)
795433d6423SLionel Sambuc {
796433d6423SLionel Sambuc   int i;
797433d6423SLionel Sambuc 
798433d6423SLionel Sambuc   if (!first) mthread_yield();
799433d6423SLionel Sambuc 
800433d6423SLionel Sambuc   /* Each new threads gets NULL-initialized values. */
801433d6423SLionel Sambuc   for (i = 0; i < 5; i++)
802433d6423SLionel Sambuc 	if (mthread_getspecific(key[i]) != NULL) err(17, 1);
803433d6423SLionel Sambuc 
804433d6423SLionel Sambuc   /* Make sure that the local values persist despite other threads' actions. */
805433d6423SLionel Sambuc   for (i = 1; i < 5; i++)
806433d6423SLionel Sambuc 	if (mthread_setspecific(key[i], (void *) i) != 0) err(17, 2);
807433d6423SLionel Sambuc 
808433d6423SLionel Sambuc   mthread_yield();
809433d6423SLionel Sambuc 
810433d6423SLionel Sambuc   for (i = 1; i < 5; i++)
811433d6423SLionel Sambuc 	if (mthread_getspecific(key[i]) != (void *) i) err(17, 3);
812433d6423SLionel Sambuc 
813433d6423SLionel Sambuc   mthread_yield();
814433d6423SLionel Sambuc 
815433d6423SLionel Sambuc   /* The other thread has deleted this key by now. */
816433d6423SLionel Sambuc   if (mthread_setspecific(key[3], NULL) != EINVAL) err(17, 4);
817433d6423SLionel Sambuc 
818433d6423SLionel Sambuc   /* If a key's value is set to NULL, its destructor must not be called. */
819433d6423SLionel Sambuc   if (mthread_setspecific(key[4], NULL) != 0) err(17, 5);
820433d6423SLionel Sambuc   return(NULL);
821433d6423SLionel Sambuc }
822433d6423SLionel Sambuc 
823433d6423SLionel Sambuc /*===========================================================================*
824433d6423SLionel Sambuc  *				key_b					     *
825433d6423SLionel Sambuc  *===========================================================================*/
key_b(void * arg)826433d6423SLionel Sambuc static void *key_b(void *arg)
827433d6423SLionel Sambuc {
828433d6423SLionel Sambuc   int i;
829433d6423SLionel Sambuc 
830433d6423SLionel Sambuc   first = 1;
831433d6423SLionel Sambuc   mthread_yield();
832433d6423SLionel Sambuc 
833433d6423SLionel Sambuc   /* Each new threads gets NULL-initialized values. */
834433d6423SLionel Sambuc   for (i = 0; i < 5; i++)
835433d6423SLionel Sambuc 	if (mthread_getspecific(key[i]) != NULL) err(18, 1);
836433d6423SLionel Sambuc 
837433d6423SLionel Sambuc   for (i = 0; i < 4; i++)
838433d6423SLionel Sambuc 	if (mthread_setspecific(key[i], (void *) (i + 2)) != 0) err(18, 2);
839433d6423SLionel Sambuc 
840433d6423SLionel Sambuc   mthread_yield();
841433d6423SLionel Sambuc 
842433d6423SLionel Sambuc   /* Deleting a key will not cause a call its destructor at any point. */
843433d6423SLionel Sambuc   if (mthread_key_delete(key[3]) != 0) err(18, 3);
844433d6423SLionel Sambuc 
845433d6423SLionel Sambuc   mthread_exit(NULL);
846433d6423SLionel Sambuc   return(NULL);
847433d6423SLionel Sambuc }
848433d6423SLionel Sambuc 
849433d6423SLionel Sambuc /*===========================================================================*
850433d6423SLionel Sambuc  *				key_c					     *
851433d6423SLionel Sambuc  *===========================================================================*/
key_c(void * arg)852433d6423SLionel Sambuc static void *key_c(void *arg)
853433d6423SLionel Sambuc {
854433d6423SLionel Sambuc   /* The only thing that this thread should do, is set a value. */
855433d6423SLionel Sambuc   if (mthread_setspecific(key[0], (void *) mthread_self()) != 0) err(19, 1);
856433d6423SLionel Sambuc 
857433d6423SLionel Sambuc   mthread_yield();
858433d6423SLionel Sambuc 
859433d6423SLionel Sambuc   if (!mthread_equal((thread_t) mthread_getspecific(key[0]), mthread_self()))
860433d6423SLionel Sambuc 	err(19, 2);
861433d6423SLionel Sambuc   return(NULL);
862433d6423SLionel Sambuc }
863433d6423SLionel Sambuc 
864433d6423SLionel Sambuc /*===========================================================================*
865433d6423SLionel Sambuc  *				test_keys				     *
866433d6423SLionel Sambuc  *===========================================================================*/
test_keys(void)867433d6423SLionel Sambuc static void test_keys(void)
868433d6423SLionel Sambuc {
869433d6423SLionel Sambuc   thread_t t[24];
870433d6423SLionel Sambuc   int i, j;
871433d6423SLionel Sambuc 
872433d6423SLionel Sambuc   /* Make sure that we can create exactly MTHREAD_KEYS_MAX keys. */
873433d6423SLionel Sambuc   memset(key, 0, sizeof(key));
874433d6423SLionel Sambuc 
875433d6423SLionel Sambuc   for (i = 0; i < MTHREAD_KEYS_MAX; i++) {
876433d6423SLionel Sambuc 	if (mthread_key_create(&key[i], NULL) != 0) err(20, 1);
877433d6423SLionel Sambuc 
878433d6423SLionel Sambuc 	for (j = 0; j < i - 1; j++)
879433d6423SLionel Sambuc 		if (key[i] == key[j]) err(20, 2);
880433d6423SLionel Sambuc   }
881433d6423SLionel Sambuc 
882433d6423SLionel Sambuc   if (mthread_key_create(&key[i], NULL) != EAGAIN) err(20, 3);
883433d6423SLionel Sambuc 
884433d6423SLionel Sambuc   for (i = 3; i < MTHREAD_KEYS_MAX; i++)
885433d6423SLionel Sambuc 	if (mthread_key_delete(key[i]) != 0) err(20, 4);
886433d6423SLionel Sambuc 
887433d6423SLionel Sambuc   /* Test basic good and bad value assignment and retrieval. */
888433d6423SLionel Sambuc   if (mthread_setspecific(key[0], (void *) 1) != 0) err(20, 5);
889433d6423SLionel Sambuc   if (mthread_setspecific(key[1], (void *) 2) != 0) err(20, 6);
890433d6423SLionel Sambuc   if (mthread_setspecific(key[2], (void *) 3) != 0) err(20, 7);
891433d6423SLionel Sambuc   if (mthread_setspecific(key[1], NULL) != 0) err(20, 8);
892433d6423SLionel Sambuc   if (mthread_getspecific(key[0]) != (void *) 1) err(20, 9);
893433d6423SLionel Sambuc   if (mthread_getspecific(key[1]) != NULL) err(20, 10);
894433d6423SLionel Sambuc   if (mthread_getspecific(key[2]) != (void *) 3) err(20, 11);
895433d6423SLionel Sambuc   if (mthread_setspecific(key[3], (void *) 4) != EINVAL) err(20, 12);
896433d6423SLionel Sambuc   if (mthread_setspecific(key[3], NULL) != EINVAL) err(20, 13);
897433d6423SLionel Sambuc 
898433d6423SLionel Sambuc   if (mthread_key_delete(key[1]) != 0) err(20, 14);
899433d6423SLionel Sambuc   if (mthread_key_delete(key[2]) != 0) err(20, 15);
900433d6423SLionel Sambuc 
901433d6423SLionel Sambuc   /* Test thread locality and destructors. */
902433d6423SLionel Sambuc   if (mthread_key_create(&key[1], destr_a) != 0) err(20, 16);
903433d6423SLionel Sambuc   if (mthread_key_create(&key[2], destr_a) != 0) err(20, 17);
904433d6423SLionel Sambuc   if (mthread_key_create(&key[3], destr_b) != 0) err(20, 18);
905433d6423SLionel Sambuc   if (mthread_key_create(&key[4], destr_b) != 0) err(20, 19);
906433d6423SLionel Sambuc 
907433d6423SLionel Sambuc   if (mthread_getspecific(key[2]) != NULL) err(20, 20);
908433d6423SLionel Sambuc 
909433d6423SLionel Sambuc   for (i = 0; i < 4; i++)
910433d6423SLionel Sambuc 	values[i] = 1;
911433d6423SLionel Sambuc   first = 0;
912433d6423SLionel Sambuc 
913433d6423SLionel Sambuc   if (mthread_create(&t[0], NULL, key_a, NULL) != 0) err(20, 21);
914433d6423SLionel Sambuc   if (mthread_create(&t[1], NULL, key_b, NULL) != 0) err(20, 22);
915433d6423SLionel Sambuc 
916433d6423SLionel Sambuc   for (i = 0; i < 2; i++)
917433d6423SLionel Sambuc 	if (mthread_join(t[i], NULL) != 0) err(20, 23);
918433d6423SLionel Sambuc 
919433d6423SLionel Sambuc   /* The destructors must have changed all these values now. */
920433d6423SLionel Sambuc   for (i = 0; i < 4; i++)
921433d6423SLionel Sambuc 	if (values[i] != 2) err(20, 24);
922433d6423SLionel Sambuc 
923433d6423SLionel Sambuc   /* The original values must not have changed. */
924433d6423SLionel Sambuc   if (mthread_getspecific(key[0]) != (void *) 1) err(20, 25);
925433d6423SLionel Sambuc 
926433d6423SLionel Sambuc   /* Deleting a deleted key should not cause any problems either. */
927433d6423SLionel Sambuc   if (mthread_key_delete(key[3]) != EINVAL) err(20, 26);
928433d6423SLionel Sambuc 
929433d6423SLionel Sambuc   /* Make sure everything still works when using a larger number of threads.
930433d6423SLionel Sambuc    * This should trigger reallocation code within libmthread's key handling.
931433d6423SLionel Sambuc    */
932433d6423SLionel Sambuc   for (i = 0; i < 24; i++)
933433d6423SLionel Sambuc 	if (mthread_create(&t[i], NULL, key_c, NULL) != 0) err(20, 27);
934433d6423SLionel Sambuc 
935433d6423SLionel Sambuc   for (i = 0; i < 24; i++)
936433d6423SLionel Sambuc 	if (mthread_join(t[i], NULL) != 0) err(20, 28);
937433d6423SLionel Sambuc }
938433d6423SLionel Sambuc 
939433d6423SLionel Sambuc /*===========================================================================*
940433d6423SLionel Sambuc  *				event_a					     *
941433d6423SLionel Sambuc  *===========================================================================*/
event_a(void * arg)942433d6423SLionel Sambuc static void *event_a(void *arg)
943433d6423SLionel Sambuc {
944433d6423SLionel Sambuc   VERIFY_EVENT(0, 0, 21, 1);
945433d6423SLionel Sambuc 
946433d6423SLionel Sambuc   /* Wait for main thread to signal us */
947433d6423SLionel Sambuc   if (mthread_event_wait(&event) != 0) err(21, 2);
948433d6423SLionel Sambuc 
949433d6423SLionel Sambuc   /* Mark state transition and wakeup thread b */
950433d6423SLionel Sambuc   event_a_step = 1;
951433d6423SLionel Sambuc   if (mthread_event_fire(&event) != 0) err(21, 3);
952433d6423SLionel Sambuc   mthread_yield();
953433d6423SLionel Sambuc   VERIFY_EVENT(1, 1, 21, 4);
954433d6423SLionel Sambuc 
955433d6423SLionel Sambuc   /* Wait for main thread to signal again with fireall  */
956433d6423SLionel Sambuc   if (mthread_event_wait(&event) != 0) err(21, 5);
957433d6423SLionel Sambuc 
958433d6423SLionel Sambuc   /* Marks state transition and exit */
959433d6423SLionel Sambuc   event_a_step = 2;
960433d6423SLionel Sambuc   return(NULL);
961433d6423SLionel Sambuc }
962433d6423SLionel Sambuc 
963433d6423SLionel Sambuc /*===========================================================================*
964433d6423SLionel Sambuc  *				event_b					     *
965433d6423SLionel Sambuc  *===========================================================================*/
event_b(void * arg)966433d6423SLionel Sambuc static void *event_b(void *arg)
967433d6423SLionel Sambuc {
968433d6423SLionel Sambuc   VERIFY_EVENT(0, 0, 22, 1);
969433d6423SLionel Sambuc 
970433d6423SLionel Sambuc   /* Wait for thread a to signal us */
971433d6423SLionel Sambuc   if (mthread_event_wait(&event) != 0) err(22, 2);
972433d6423SLionel Sambuc   VERIFY_EVENT(1, 0, 22, 3);
973433d6423SLionel Sambuc 
974433d6423SLionel Sambuc   /* Mark state transition and wait again, this time for main thread */
975433d6423SLionel Sambuc   event_b_step = 1;
976433d6423SLionel Sambuc   if (mthread_event_wait(&event) != 0) err(21, 5);
977433d6423SLionel Sambuc 
978433d6423SLionel Sambuc   /* Marks state transition and exit */
979433d6423SLionel Sambuc   event_b_step = 2;
980433d6423SLionel Sambuc   return(NULL);
981433d6423SLionel Sambuc }
982433d6423SLionel Sambuc 
983433d6423SLionel Sambuc /*===========================================================================*
984433d6423SLionel Sambuc  *				test_event				     *
985433d6423SLionel Sambuc  *===========================================================================*/
test_event(void)986433d6423SLionel Sambuc static void test_event(void)
987433d6423SLionel Sambuc {
988433d6423SLionel Sambuc   thread_t t[2];
989433d6423SLionel Sambuc   int i;
990433d6423SLionel Sambuc 
991433d6423SLionel Sambuc   if (mthread_event_init(&event) != 0) err(23, 1);
992433d6423SLionel Sambuc 
993433d6423SLionel Sambuc   /* Try with faulty memory locations */
994433d6423SLionel Sambuc   if (mthread_event_wait(NULL) == 0) err(23, 2);
995433d6423SLionel Sambuc   if (mthread_event_fire(NULL) == 0) err(23, 3);
996433d6423SLionel Sambuc 
997433d6423SLionel Sambuc   /* create threads */
998433d6423SLionel Sambuc   if (mthread_create(&t[0], NULL, event_a, NULL) != 0) err(23, 4);
999433d6423SLionel Sambuc   if (mthread_create(&t[1], NULL, event_b, NULL) != 0) err(23, 5);
1000433d6423SLionel Sambuc 
1001433d6423SLionel Sambuc   /* wait for them to block on event */
1002433d6423SLionel Sambuc   mthread_yield_all();
1003433d6423SLionel Sambuc   VERIFY_EVENT(0, 0, 23, 6);
1004433d6423SLionel Sambuc 
1005433d6423SLionel Sambuc   /* Fire event to wakeup thread a */
1006433d6423SLionel Sambuc   if (mthread_event_fire(&event) != 0) err(23, 7);
1007433d6423SLionel Sambuc   mthread_yield_all();
1008433d6423SLionel Sambuc   VERIFY_EVENT(1, 1, 23, 6);
1009433d6423SLionel Sambuc 
1010433d6423SLionel Sambuc   /* Fire all to wakeup both a and b */
1011433d6423SLionel Sambuc   if (mthread_event_fire_all(&event) != 0) err(23, 7);
1012433d6423SLionel Sambuc   mthread_yield_all();
1013433d6423SLionel Sambuc   VERIFY_EVENT(2, 2, 23, 8);
1014433d6423SLionel Sambuc 
1015433d6423SLionel Sambuc   /* We are done here */
1016433d6423SLionel Sambuc   for (i = 0; i < 2; i++)
1017433d6423SLionel Sambuc 	if (mthread_join(t[i], NULL) != 0) err(23, 9);
1018433d6423SLionel Sambuc 
1019433d6423SLionel Sambuc   if (mthread_event_destroy(&event) != 0) err(23, 10);
1020433d6423SLionel Sambuc }
1021433d6423SLionel Sambuc 
1022433d6423SLionel Sambuc /*===========================================================================*
1023433d6423SLionel Sambuc  *				rwlock_a				     *
1024433d6423SLionel Sambuc  *===========================================================================*/
rwlock_a(void * arg)1025433d6423SLionel Sambuc static void *rwlock_a(void *arg)
1026433d6423SLionel Sambuc {
1027433d6423SLionel Sambuc   /* acquire read lock */
1028433d6423SLionel Sambuc   VERIFY_RWLOCK(0, 0, 24, 1);
1029433d6423SLionel Sambuc   if (mthread_rwlock_rdlock(&rwlock) != 0) err(24, 2);
1030433d6423SLionel Sambuc   rwlock_a_step = 1;
1031433d6423SLionel Sambuc   mthread_yield();
1032433d6423SLionel Sambuc 
1033433d6423SLionel Sambuc   /* release read lock */
1034433d6423SLionel Sambuc   VERIFY_RWLOCK(1, 1, 24, 3);
1035433d6423SLionel Sambuc   if (mthread_rwlock_unlock(&rwlock) != 0) err(24, 4);
1036433d6423SLionel Sambuc   rwlock_a_step = 2;
1037433d6423SLionel Sambuc 
1038433d6423SLionel Sambuc   /* get write lock */
1039433d6423SLionel Sambuc   if (mthread_rwlock_wrlock(&rwlock) != 0) err(24, 5);
1040433d6423SLionel Sambuc   rwlock_a_step = 3;
1041433d6423SLionel Sambuc   VERIFY_RWLOCK(3, 2, 24, 6);
1042433d6423SLionel Sambuc 
1043433d6423SLionel Sambuc   /* release write lock */
1044433d6423SLionel Sambuc   if (mthread_rwlock_unlock(&rwlock) != 0) err(24, 7);
1045433d6423SLionel Sambuc   mthread_yield();
1046433d6423SLionel Sambuc 
1047433d6423SLionel Sambuc   VERIFY_RWLOCK(3, 3, 24, 8);
1048433d6423SLionel Sambuc 
1049433d6423SLionel Sambuc   return(NULL);
1050433d6423SLionel Sambuc }
1051433d6423SLionel Sambuc 
1052433d6423SLionel Sambuc /*===========================================================================*
1053433d6423SLionel Sambuc  *				rwlock_b				     *
1054433d6423SLionel Sambuc  *===========================================================================*/
rwlock_b(void * arg)1055433d6423SLionel Sambuc static void *rwlock_b(void *arg)
1056433d6423SLionel Sambuc {
1057433d6423SLionel Sambuc   /* Step 1: acquire the read lock */
1058433d6423SLionel Sambuc   VERIFY_RWLOCK(1, 0, 25, 1);
1059433d6423SLionel Sambuc   if (mthread_rwlock_rdlock(&rwlock) != 0) err(25, 2);
1060433d6423SLionel Sambuc   rwlock_b_step = 1;
1061433d6423SLionel Sambuc   mthread_yield();
1062433d6423SLionel Sambuc 
1063433d6423SLionel Sambuc   /* We return back with first thread blocked on wrlock */
1064433d6423SLionel Sambuc   VERIFY_RWLOCK(2, 1, 25, 3);
1065433d6423SLionel Sambuc   rwlock_b_step = 2;
1066433d6423SLionel Sambuc 
1067433d6423SLionel Sambuc   /* Release read lock and acquire write lock */
1068433d6423SLionel Sambuc   if (mthread_rwlock_unlock(&rwlock) != 0) err(25, 4);
1069433d6423SLionel Sambuc   if (mthread_rwlock_wrlock(&rwlock) != 0) err(25, 5);
1070433d6423SLionel Sambuc   rwlock_b_step = 3;
1071433d6423SLionel Sambuc 
1072433d6423SLionel Sambuc   VERIFY_RWLOCK(3, 3, 25, 6);
1073433d6423SLionel Sambuc   if (mthread_rwlock_unlock(&rwlock) != 0) err(25, 6);
1074433d6423SLionel Sambuc 
1075433d6423SLionel Sambuc   return(NULL);
1076433d6423SLionel Sambuc }
1077433d6423SLionel Sambuc 
1078433d6423SLionel Sambuc /*===========================================================================*
1079433d6423SLionel Sambuc  *				test_rwlock				     *
1080433d6423SLionel Sambuc  *===========================================================================*/
test_rwlock(void)1081433d6423SLionel Sambuc static void test_rwlock(void)
1082433d6423SLionel Sambuc {
1083433d6423SLionel Sambuc   thread_t t[2];
1084433d6423SLionel Sambuc   int i;
1085433d6423SLionel Sambuc 
1086433d6423SLionel Sambuc   if (mthread_rwlock_init(&rwlock) != 0) err(26, 1);
1087433d6423SLionel Sambuc 
1088433d6423SLionel Sambuc   /* Try with faulty memory locations */
1089433d6423SLionel Sambuc   if (mthread_rwlock_rdlock(NULL) == 0) err(26, 2);
1090433d6423SLionel Sambuc   if (mthread_rwlock_wrlock(NULL) == 0) err(26, 3);
1091433d6423SLionel Sambuc   if (mthread_rwlock_unlock(NULL) == 0) err(26, 4);
1092433d6423SLionel Sambuc 
1093433d6423SLionel Sambuc   /* Create the threads and start testing */
1094433d6423SLionel Sambuc   if (mthread_create(&t[0], NULL, rwlock_a, NULL) != 0) err(26, 5);
1095433d6423SLionel Sambuc   if (mthread_create(&t[1], NULL, rwlock_b, NULL) != 0) err(26, 6);
1096433d6423SLionel Sambuc 
1097433d6423SLionel Sambuc   mthread_yield_all();
1098433d6423SLionel Sambuc 
1099433d6423SLionel Sambuc   for (i = 0; i < 2; i++)
1100433d6423SLionel Sambuc 	if (mthread_join(t[i], NULL) != 0) err(26, 7);
1101433d6423SLionel Sambuc 
1102433d6423SLionel Sambuc   if (mthread_rwlock_destroy(&rwlock) != 0) err(26, 8);
1103433d6423SLionel Sambuc }
1104433d6423SLionel Sambuc 
1105433d6423SLionel Sambuc 
1106433d6423SLionel Sambuc /*===========================================================================*
1107433d6423SLionel Sambuc  *				main					     *
1108433d6423SLionel Sambuc  *===========================================================================*/
main(void)1109433d6423SLionel Sambuc int main(void)
1110433d6423SLionel Sambuc {
1111433d6423SLionel Sambuc   errct = 0;
1112433d6423SLionel Sambuc   th_a = th_b = th_c = th_d = th_e = th_f = th_g = th_h = 0;
1113433d6423SLionel Sambuc   mutex_a_step = mutex_b_step = mutex_c_step = 0;
1114433d6423SLionel Sambuc   event_a_step = event_b_step = 0;
1115433d6423SLionel Sambuc   rwlock_a_step = rwlock_b_step = 0;
1116433d6423SLionel Sambuc   once = MTHREAD_ONCE_INIT;
1117433d6423SLionel Sambuc 
1118433d6423SLionel Sambuc   start(59);
1119433d6423SLionel Sambuc   test_scheduling();
1120433d6423SLionel Sambuc   test_mutex();
1121433d6423SLionel Sambuc   test_event();
1122433d6423SLionel Sambuc   test_rwlock();
1123433d6423SLionel Sambuc   test_condition();
1124433d6423SLionel Sambuc   test_attributes();
1125433d6423SLionel Sambuc   test_keys();
1126433d6423SLionel Sambuc   quit();
1127433d6423SLionel Sambuc   return(0);	/* Not reachable */
1128433d6423SLionel Sambuc }
1129433d6423SLionel Sambuc 
1130