1 /*
2  * %CopyrightBegin%
3  *
4  * Copyright Ericsson AB 2004-2016. All Rights Reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  * %CopyrightEnd%
19  */
20 
21 /*
22  * Description: Test suite for the ethread thread library.
23  * Author: Rickard Green
24  */
25 
26 #define ETHR_NO_SUPP_THR_LIB_NOT_FATAL
27 #include "ethread.h"
28 #include "erl_misc_utils.h"
29 
30 #include <stdio.h>
31 #include <stdarg.h>
32 #include <string.h>
33 #ifndef __WIN32__
34 #include <unistd.h>
35 #endif
36 #include <limits.h>
37 
38 /*
39  * Auxiliary functions
40  */
41 
42 #define PRINT_VA_LIST(FRMT)						\
43 do {									\
44     if (FRMT && FRMT != '\0') {						\
45 	va_list args;							\
46 	va_start(args, FRMT);						\
47 	vfprintf(stderr, FRMT, args);					\
48 	va_end(args);							\
49     }									\
50 } while (0)
51 
52 #define ASSERT(B)							\
53 do {									\
54     if (!(B))								\
55 	fail("%s:%d: Assertion \"%s\" failed!",__FILE__,__LINE__,#B);	\
56 } while (0)
57 
58 
59 #define ASSERT_PRINT(B, PRNT)						\
60 do {									\
61     if (!(B)) {								\
62 	print PRNT;							\
63 	fail("%s:%d: Assertion \"%s\" failed!",__FILE__,__LINE__,#B);	\
64     }									\
65 } while (0)
66 
67 #define ASSERT_EQ(VAR, VAL, FSTR)					\
68 do {									\
69     if ((VAR) != (VAL)) {						\
70 	print("%s=" FSTR "\n", #VAR, (VAR));				\
71 	fail("%s:%d: Assertion \"%s == " FSTR "\" failed!",		\
72 	     __FILE__, __LINE__, #VAR, (VAL));				\
73     }									\
74 } while (0)
75 
76 #ifdef __WIN32_
77 #define EOL "\r\n"
78 #else
79 #define EOL "\n"
80 #endif
81 
82 static void
print_eol(void)83 print_eol(void)
84 {
85     fprintf(stderr, EOL);
86     fflush(stderr);
87 }
88 
print_line(char * frmt,...)89 static void print_line(char *frmt,...)
90 {
91     PRINT_VA_LIST(frmt);
92     print_eol();
93 }
94 
95 #if 0 /* Currently not used; silence annoying warning... */
96 static void print(char *frmt,...)
97 {
98     PRINT_VA_LIST(frmt);
99 }
100 #endif
101 
fail(char * frmt,...)102 static void fail(char *frmt,...)
103 {
104     char *abrt_env;
105     print_eol();
106     fprintf(stderr, "ETHR-TEST-FAILURE");
107     PRINT_VA_LIST(frmt);
108     print_eol();
109     abrt_env = getenv("ERL_ABORT_ON_FAILURE");
110     if (abrt_env && strcmp("true", abrt_env) == 0)
111 	abort();
112     else
113 	exit(1);
114 }
115 
skip(char * frmt,...)116 static void skip(char *frmt,...)
117 {
118     print_eol();
119     fprintf(stderr, "ETHR-TEST-SKIP");
120     PRINT_VA_LIST(frmt);
121     print_eol();
122     exit(0);
123 }
124 
succeed(char * frmt,...)125 static void succeed(char *frmt,...)
126 {
127     print_eol();
128     fprintf(stderr, "ETHR-TEST-SUCCESS");
129     PRINT_VA_LIST(frmt);
130     print_eol();
131     exit(0);
132 }
133 
134 static void
do_sleep(unsigned secs)135 do_sleep(unsigned secs)
136 {
137     while (erts_milli_sleep(secs*1000) != 0);
138 }
139 
140 #define WAIT_UNTIL_INTERVAL 10
141 
142 #define WAIT_UNTIL_LIM(TEST, LIM)				\
143 do {								\
144     int ms__ = (LIM)*1000;					\
145     while (!(TEST)) {						\
146 	while (erts_milli_sleep(WAIT_UNTIL_INTERVAL) != 0);	\
147 	ms__ -= WAIT_UNTIL_INTERVAL;				\
148 	if (ms__ <= 0)						\
149 	    break;						\
150     }								\
151 } while (0)
152 
153 static void
send_my_pid(void)154 send_my_pid(void)
155 {
156 #ifndef __WIN32__
157     int pid = (int) getpid();
158     fprintf(stderr, EOL "ETHR-TEST-PID%d" EOL, pid);
159 #endif
160 }
161 
162 /*
163  * The test-cases
164  */
165 
166 #ifndef ETHR_NO_THREAD_LIB
167 
168 /*
169  * The create join thread test case.
170  *
171  * Tests ethr_thr_create and ethr_thr_join.
172  */
173 
174 #define CJTT_NO_THREADS 64
175 ethr_tid cjtt_tids[CJTT_NO_THREADS + 1];
176 int cjtt_ix[CJTT_NO_THREADS + 1];
177 int cjtt_res[CJTT_NO_THREADS + 1];
cjtt_thread(void * vpix)178 void *cjtt_thread(void *vpix)
179 {
180     int ix = *((int *) vpix);
181     cjtt_res[ix] = ix;
182     return (void *) &cjtt_res[ix];
183 }
184 
185 static void
create_join_thread_test(void)186 create_join_thread_test(void)
187 {
188     int i, res;
189 
190     for (i = 1; i <= CJTT_NO_THREADS; i++) {
191 	cjtt_ix[i] = i;
192 	cjtt_res[i] = 0;
193     }
194 
195     for (i = 1; i <= CJTT_NO_THREADS; i++) {
196 	res = ethr_thr_create(&cjtt_tids[i],
197 			      cjtt_thread,
198 			      (void *) &cjtt_ix[i],
199 			      NULL);
200 	ASSERT(res == 0);
201     }
202 
203     for (i = 1; i <= CJTT_NO_THREADS; i++) {
204 	void *tres;
205 	res = ethr_thr_join(cjtt_tids[i], &tres);
206 	ASSERT(res == 0);
207 	ASSERT(tres == &cjtt_res[i]);
208 	ASSERT(cjtt_res[i] == i);
209     }
210 
211 }
212 
213 
214 /*
215  * The eq tid test case.
216  *
217  * Tests ethr_equal_tids.
218  */
219 
220 #define ETT_THREADS 1000
221 
222 static ethr_tid ett_tids[3];
223 static ethr_mutex ett_mutex;
224 static ethr_cond ett_cond;
225 static int ett_terminate;
226 static int ett_thread_go;
227 
228 static void *
ett_thread(void * my_tid)229 ett_thread(void *my_tid)
230 {
231     ethr_mutex_lock(&ett_mutex);
232     while (!ett_thread_go) {
233 	int res = ethr_cond_wait(&ett_cond, &ett_mutex);
234 	ASSERT(res == 0);
235     }
236     ethr_mutex_unlock(&ett_mutex);
237 
238     ASSERT(!ethr_equal_tids(ethr_self(), ett_tids[0]));
239     ASSERT(ethr_equal_tids(ethr_self(), *((ethr_tid *) my_tid)));
240 
241     return NULL;
242 }
243 
244 static void *
ett_thread2(void * unused)245 ett_thread2(void *unused)
246 {
247     int res;
248     ethr_mutex_lock(&ett_mutex);
249     while (!ett_terminate) {
250 	res = ethr_cond_wait(&ett_cond, &ett_mutex);
251 	ASSERT(res == 0);
252     }
253     ethr_mutex_unlock(&ett_mutex);
254     return NULL;
255 }
256 
257 static void
equal_tids_test(void)258 equal_tids_test(void)
259 {
260     int res, i;
261 
262     res = ethr_mutex_init(&ett_mutex);
263     ASSERT(res == 0);
264     res = ethr_cond_init(&ett_cond);
265     ASSERT(res == 0);
266     ett_tids[0] = ethr_self();
267 
268     ethr_mutex_lock(&ett_mutex);
269     ett_thread_go = 0;
270     ethr_mutex_unlock(&ett_mutex);
271 
272     res = ethr_thr_create(&ett_tids[1], ett_thread, (void *) &ett_tids[1], NULL);
273     ASSERT(res == 0);
274 
275     ethr_mutex_lock(&ett_mutex);
276     ett_thread_go = 1;
277     ethr_cond_signal(&ett_cond);
278     ethr_mutex_unlock(&ett_mutex);
279 
280     ASSERT(ethr_equal_tids(ethr_self(), ett_tids[0]));
281     ASSERT(!ethr_equal_tids(ethr_self(), ett_tids[1]));
282 
283     res = ethr_thr_join(ett_tids[1], NULL);
284 
285     ethr_mutex_lock(&ett_mutex);
286     ett_thread_go = 0;
287     ethr_mutex_unlock(&ett_mutex);
288 
289     res = ethr_thr_create(&ett_tids[2], ett_thread, (void *) &ett_tids[2], NULL);
290     ASSERT(res == 0);
291 
292     ethr_mutex_lock(&ett_mutex);
293     ett_thread_go = 1;
294     ethr_cond_signal(&ett_cond);
295     ethr_mutex_unlock(&ett_mutex);
296 
297     ASSERT(ethr_equal_tids(ethr_self(), ett_tids[0]));
298     ASSERT(!ethr_equal_tids(ethr_self(), ett_tids[1]));
299     ASSERT(!ethr_equal_tids(ethr_self(), ett_tids[2]));
300 
301 #if 0
302     /* This fails on some linux platforms. Until we decides if a tid
303      * is allowed to be reused right away or not, we disable the test.
304      */
305 
306     ASSERT(!ethr_equal_tids(ett_tids[1], ett_tids[2]));
307 #endif
308 
309     res = ethr_thr_join(ett_tids[2], NULL);
310     ASSERT(res == 0);
311 
312     /* Second part of test */
313 
314     ett_terminate = 0;
315 
316     res = ethr_thr_create(&ett_tids[1], ett_thread2, NULL, NULL);
317     ASSERT(res == 0);
318 
319     ASSERT(!ethr_equal_tids(ett_tids[0], ett_tids[1]));
320 
321     for (i = 0; i < ETT_THREADS; i++) {
322         ethr_mutex_lock(&ett_mutex);
323         ett_thread_go = 0;
324         ethr_mutex_unlock(&ett_mutex);
325 
326 	res = ethr_thr_create(&ett_tids[2], ett_thread, (void*)&ett_tids[2], NULL);
327 	ASSERT(res == 0);
328 
329         ethr_mutex_lock(&ett_mutex);
330         ett_thread_go = 1;
331         ethr_cond_broadcast(&ett_cond);
332         ethr_mutex_unlock(&ett_mutex);
333 
334 	ASSERT(!ethr_equal_tids(ett_tids[0], ett_tids[2]));
335 	ASSERT(!ethr_equal_tids(ett_tids[1], ett_tids[2]));
336 
337 	res = ethr_thr_join(ett_tids[2], NULL);
338 	ASSERT(res == 0);
339     }
340 
341     ethr_mutex_lock(&ett_mutex);
342     ett_terminate = 1;
343     ethr_cond_signal(&ett_cond);
344     ethr_mutex_unlock(&ett_mutex);
345     res = ethr_thr_join(ett_tids[1], NULL);
346     ASSERT(res == 0);
347 
348     res = ethr_cond_destroy(&ett_cond);
349     ASSERT(res == 0);
350     res = ethr_mutex_destroy(&ett_mutex);
351     ASSERT(res == 0);
352 
353 }
354 
355 /*
356  * The mutex test case.
357  *
358  * Tests mutexes.
359  */
360 
361 static ethr_mutex mt_mutex;
362 static int mt_data;
363 
364 void *
mt_thread(void * unused)365 mt_thread(void *unused)
366 {
367     print_line("Aux thread tries to lock mutex");
368     ethr_mutex_lock(&mt_mutex);
369     print_line("Aux thread locked mutex");
370 
371     ASSERT(mt_data == 0);
372 
373     mt_data = 1;
374     print_line("Aux thread wrote");
375 
376     print_line("Aux thread goes to sleep for 1 second");
377     do_sleep(1);
378     print_line("Aux thread woke up");
379 
380     ASSERT(mt_data == 1);
381 
382     ethr_mutex_unlock(&mt_mutex);
383     print_line("Aux thread unlocked mutex");
384 
385     return NULL;
386 }
387 
388 
389 static void
mutex_test(void)390 mutex_test(void)
391 {
392     int res;
393     ethr_tid tid;
394 
395     print_line("Trying to initialize mutex");
396     res = ethr_mutex_init(&mt_mutex);
397     ASSERT(res == 0);
398     print_line("Initialized mutex");
399 
400     mt_data = 0;
401 
402     print_line("Main thread tries to lock mutex");
403     ethr_mutex_lock(&mt_mutex);
404     print_line("Main thread locked mutex");
405 
406     ASSERT(mt_data == 0);
407 
408     print_line("Main thread about to create aux thread");
409     res = ethr_thr_create(&tid, mt_thread, NULL, NULL);
410     ASSERT(res == 0);
411     print_line("Main thread created aux thread");
412 
413     print_line("Main thread goes to sleep for 1 second");
414     do_sleep(1);
415     print_line("Main thread woke up");
416 
417     ASSERT(mt_data == 0);
418 
419     ethr_mutex_unlock(&mt_mutex);
420     print_line("Main thread unlocked mutex");
421 
422     print_line("Main thread goes to sleep for 1 second");
423     do_sleep(1);
424     print_line("Main thread woke up");
425 
426     print_line("Main thread tries to lock mutex");
427     ethr_mutex_lock(&mt_mutex);
428     print_line("Main thread locked mutex");
429 
430     ASSERT(mt_data == 1);
431 
432     print_line("Main thread goes to sleep for 1 second");
433     do_sleep(1);
434     print_line("Main thread woke up");
435 
436     ASSERT(mt_data == 1);
437 
438     ethr_mutex_unlock(&mt_mutex);
439     print_line("Main thread unlocked mutex");
440 
441     res = ethr_thr_join(tid, NULL);
442     ASSERT(res == 0);
443     print_line("Main thread joined aux thread");
444 
445     res = ethr_mutex_destroy(&mt_mutex);
446     ASSERT(res == 0);
447     print_line("Main thread destroyed mutex");
448 
449 }
450 
451 /*
452  * The try lock mutex test case.
453  *
454  * Tests try lock mutex operation.
455  */
456 
457 static ethr_mutex tlmt_mtx1;
458 static ethr_mutex tlmt_mtx2;
459 static ethr_cond tlmt_cnd2;
460 
461 static int tlmt_mtx1_locked;
462 static int tlmt_mtx1_do_unlock;
463 
464 static void *
tlmt_thread(void * unused)465 tlmt_thread(void *unused)
466 {
467     int res;
468 
469     ethr_mutex_lock(&tlmt_mtx1);
470     ethr_mutex_lock(&tlmt_mtx2);
471 
472     tlmt_mtx1_locked = 1;
473     ethr_cond_signal(&tlmt_cnd2);
474 
475     while (!tlmt_mtx1_do_unlock) {
476 	res = ethr_cond_wait(&tlmt_cnd2, &tlmt_mtx2);
477 	ASSERT(res == 0 || res == EINTR);
478     }
479 
480     ethr_mutex_unlock(&tlmt_mtx2);
481     ethr_mutex_unlock(&tlmt_mtx1);
482 
483     ethr_mutex_lock(&tlmt_mtx2);
484     tlmt_mtx1_locked = 0;
485     ethr_cond_signal(&tlmt_cnd2);
486     ethr_mutex_unlock(&tlmt_mtx2);
487 
488     return NULL;
489 }
490 
491 static void
try_lock_mutex_test(void)492 try_lock_mutex_test(void)
493 {
494     int i, res;
495     ethr_tid tid;
496 
497     res = ethr_mutex_init(&tlmt_mtx1);
498     ASSERT(res == 0);
499     res = ethr_mutex_init(&tlmt_mtx2);
500     ASSERT(res == 0);
501     res = ethr_cond_init(&tlmt_cnd2);
502     ASSERT(res == 0);
503 
504     tlmt_mtx1_locked = 0;
505     tlmt_mtx1_do_unlock = 0;
506 
507     res = ethr_thr_create(&tid, tlmt_thread, NULL, NULL);
508     ASSERT(res == 0);
509 
510     ethr_mutex_lock(&tlmt_mtx2);
511 
512     while (!tlmt_mtx1_locked) {
513 	res = ethr_cond_wait(&tlmt_cnd2, &tlmt_mtx2);
514 	ASSERT(res == 0 || res == EINTR);
515     }
516 
517     ethr_mutex_unlock(&tlmt_mtx2);
518 
519     for (i = 0; i < 10; i++) {
520 	res = ethr_mutex_trylock(&tlmt_mtx1);
521 	ASSERT(res == EBUSY);
522     }
523 
524     ethr_mutex_lock(&tlmt_mtx2);
525 
526     tlmt_mtx1_do_unlock = 1;
527     ethr_cond_signal(&tlmt_cnd2);
528 
529     while (tlmt_mtx1_locked) {
530 	res = ethr_cond_wait(&tlmt_cnd2, &tlmt_mtx2);
531 	ASSERT(res == 0 || res == EINTR);
532     }
533 
534     ethr_mutex_unlock(&tlmt_mtx2);
535 
536     res = ethr_mutex_trylock(&tlmt_mtx1);
537     ASSERT(res == 0);
538 
539     ethr_mutex_unlock(&tlmt_mtx1);
540 
541     res = ethr_thr_join(tid, NULL);
542     ASSERT(res == 0);
543 
544     res = ethr_mutex_destroy(&tlmt_mtx1);
545     ASSERT(res == 0);
546     res = ethr_mutex_destroy(&tlmt_mtx2);
547     ASSERT(res == 0);
548     res = ethr_cond_destroy(&tlmt_cnd2);
549     ASSERT(res == 0);
550 }
551 
552 /*
553  * The cond wait test case.
554  *
555  * Tests ethr_cond_wait with ethr_cond_signal and ethr_cond_broadcast.
556  */
557 
558 
559 static ethr_mutex cwt_mutex;
560 static ethr_cond cwt_cond;
561 static int cwt_counter;
562 
563 void *
cwt_thread(void * unused)564 cwt_thread(void *unused)
565 {
566     int res;
567 
568     ethr_mutex_lock(&cwt_mutex);
569 
570     do {
571 	res = ethr_cond_wait(&cwt_cond, &cwt_mutex);
572     } while (res == EINTR);
573     ASSERT(res == 0);
574 
575     cwt_counter++;
576 
577     ethr_mutex_unlock(&cwt_mutex);
578 
579     return NULL;
580 }
581 
582 static void
cond_wait_test(void)583 cond_wait_test(void)
584 {
585     ethr_tid tid1, tid2;
586     int res;
587 
588     res = ethr_mutex_init(&cwt_mutex);
589     ASSERT(res == 0);
590     res = ethr_cond_init(&cwt_cond);
591     ASSERT(res == 0);
592 
593     /* Wake with signal */
594 
595     cwt_counter = 0;
596 
597     res = ethr_thr_create(&tid1, cwt_thread, NULL, NULL);
598     ASSERT(res == 0);
599     res = ethr_thr_create(&tid2, cwt_thread, NULL, NULL);
600     ASSERT(res == 0);
601 
602     do_sleep(1); /* Make sure threads waits on cond var */
603 
604     ethr_mutex_lock(&cwt_mutex);
605 
606     ethr_cond_signal(&cwt_cond); /* Wake one thread */
607 
608     do_sleep(1); /* Make sure awakened thread waits on mutex */
609 
610     ASSERT(cwt_counter == 0);
611 
612     ethr_mutex_unlock(&cwt_mutex);
613 
614     do_sleep(1);  /* Let awakened thread proceed */
615 
616     ethr_mutex_lock(&cwt_mutex);
617 
618     ASSERT(cwt_counter == 1);
619 
620     ethr_cond_signal(&cwt_cond); /* Wake the other thread */
621 
622     do_sleep(1); /* Make sure awakened thread waits on mutex */
623 
624     ASSERT(cwt_counter == 1);
625 
626     ethr_mutex_unlock(&cwt_mutex);
627 
628     do_sleep(1);  /* Let awakened thread proceed */
629 
630     ethr_mutex_lock(&cwt_mutex);
631 
632     ASSERT(cwt_counter == 2);
633 
634     ethr_mutex_unlock(&cwt_mutex);
635 
636     res = ethr_thr_join(tid1, NULL);
637     ASSERT(res == 0);
638 
639     res = ethr_thr_join(tid2, NULL);
640     ASSERT(res == 0);
641 
642 
643     /* Wake with broadcast */
644 
645     cwt_counter = 0;
646 
647     res = ethr_thr_create(&tid1, cwt_thread, NULL, NULL);
648     ASSERT(res == 0);
649     res = ethr_thr_create(&tid2, cwt_thread, NULL, NULL);
650     ASSERT(res == 0);
651 
652     do_sleep(1); /* Make sure threads waits on cond var */
653 
654     ethr_mutex_lock(&cwt_mutex);
655 
656     ethr_cond_broadcast(&cwt_cond); /* Wake the threads */
657 
658     do_sleep(1); /* Make sure awakened threads wait on mutex */
659 
660     ASSERT(cwt_counter == 0);
661 
662     ethr_mutex_unlock(&cwt_mutex);
663 
664     do_sleep(1);  /* Let awakened threads proceed */
665 
666     ethr_mutex_lock(&cwt_mutex);
667 
668     ASSERT(cwt_counter == 2);
669 
670     ethr_mutex_unlock(&cwt_mutex);
671 
672     res = ethr_thr_join(tid1, NULL);
673     ASSERT(res == 0);
674 
675     res = ethr_thr_join(tid2, NULL);
676     ASSERT(res == 0);
677 
678     res = ethr_mutex_destroy(&cwt_mutex);
679     ASSERT(res == 0);
680     res = ethr_cond_destroy(&cwt_cond);
681     ASSERT(res == 0);
682 
683 }
684 
685 /*
686  * The broadcast test case.
687  *
688  * Tests that a ethr_cond_broadcast really wakes up all waiting threads.
689  */
690 
691 #define BCT_THREADS 64
692 #define BCT_NO_OF_WAITS 100
693 
694 static int bct_woken = 0;
695 static int bct_waiting = 0;
696 static int bct_done = 0;
697 static ethr_mutex bct_mutex;
698 static ethr_cond bct_cond;
699 static ethr_cond bct_cntrl_cond;
700 
701 
702 static void *
bct_thread(void * unused)703 bct_thread(void *unused)
704 {
705     int res;
706 
707     ethr_mutex_lock(&bct_mutex);
708 
709     while (!bct_done) {
710 
711 	bct_waiting++;
712 	if (bct_waiting == BCT_THREADS)
713 	    ethr_cond_signal(&bct_cntrl_cond);
714 	do {
715 	    res = ethr_cond_wait(&bct_cond, &bct_mutex);
716 	} while (res == EINTR);
717 	ASSERT(res == 0);
718 	bct_woken++;
719 	if (bct_woken == BCT_THREADS)
720 	    ethr_cond_signal(&bct_cntrl_cond);
721 
722     }
723 
724     ethr_mutex_unlock(&bct_mutex);
725 
726     return NULL;
727 }
728 
729 static void
broadcast_test(void)730 broadcast_test(void)
731 {
732     int res, i;
733     ethr_tid tid[BCT_THREADS];
734 
735     res = ethr_mutex_init(&bct_mutex);
736     ASSERT(res == 0);
737     res = ethr_cond_init(&bct_cntrl_cond);
738     ASSERT(res == 0);
739     res = ethr_cond_init(&bct_cond);
740     ASSERT(res == 0);
741 
742     for (i = 0; i < BCT_THREADS; i++) {
743 	res = ethr_thr_create(&tid[i], bct_thread, NULL, NULL);
744 	ASSERT(res == 0);
745 
746     }
747 
748     ethr_mutex_lock(&bct_mutex);
749 
750     for (i = 0; i < BCT_NO_OF_WAITS; i++) {
751 
752 	while (bct_waiting != BCT_THREADS) {
753 	    res = ethr_cond_wait(&bct_cntrl_cond, &bct_mutex);
754 	    ASSERT(res == 0 || res == EINTR);
755 	}
756 
757 	bct_waiting = 0;
758 	bct_woken = 0;
759 
760 	/* Wake all threads */
761 	ethr_cond_broadcast(&bct_cond);
762 
763 	while (bct_woken != BCT_THREADS) {
764 	    res = ethr_cond_wait(&bct_cntrl_cond, &bct_mutex);
765 	    ASSERT(res == 0 || res == EINTR);
766 	}
767 
768     }
769 
770     bct_done = 1;
771 
772     /* Wake all threads */
773     ethr_cond_broadcast(&bct_cond);
774 
775     ethr_mutex_unlock(&bct_mutex);
776 
777     for (i = 0; i < BCT_THREADS; i++) {
778 	res = ethr_thr_join(tid[i], NULL);
779 	ASSERT(res == 0);
780     }
781 
782     res = ethr_mutex_destroy(&bct_mutex);
783     ASSERT(res == 0);
784     res = ethr_cond_destroy(&bct_cntrl_cond);
785     ASSERT(res == 0);
786     res = ethr_cond_destroy(&bct_cond);
787     ASSERT(res == 0);
788 
789 }
790 
791 /*
792  * The detached thread test case.
793  *
794  * Tests detached threads.
795  */
796 
797 #define DT_THREADS (50*1024)
798 #define DT_BATCH_SIZE 64
799 
800 static ethr_mutex dt_mutex;
801 static ethr_cond dt_cond;
802 static int dt_count;
803 static int dt_limit;
804 
805 static void *
dt_thread(void * unused)806 dt_thread(void *unused)
807 {
808     ethr_mutex_lock(&dt_mutex);
809 
810     dt_count++;
811 
812     if (dt_count >= dt_limit)
813 	ethr_cond_signal(&dt_cond);
814 
815     ethr_mutex_unlock(&dt_mutex);
816 
817     return NULL;
818 }
819 
820 static void
detached_thread_test(void)821 detached_thread_test(void)
822 {
823     ethr_thr_opts thr_opts = ETHR_THR_OPTS_DEFAULT_INITER;
824     ethr_tid tid[DT_BATCH_SIZE];
825     int i, j, res;
826 
827     res = ethr_mutex_init(&dt_mutex);
828     ASSERT(res == 0);
829     res = ethr_cond_init(&dt_cond);
830     ASSERT(res == 0);
831 
832     thr_opts.detached = 1;
833     dt_count = 0;
834     dt_limit = 0;
835 
836     for (i = 0; i < DT_THREADS/DT_BATCH_SIZE; i++) {
837 
838 	dt_limit += DT_BATCH_SIZE;
839 
840 	for (j = 0; j < DT_BATCH_SIZE; j++) {
841 	    res = ethr_thr_create(&tid[j], dt_thread, NULL, &thr_opts);
842 	    ASSERT(res == 0);
843 	}
844 
845 	ethr_mutex_lock(&dt_mutex);
846 	while (dt_count < dt_limit) {
847 	    res = ethr_cond_wait(&dt_cond, &dt_mutex);
848 	    ASSERT(res == 0 || res == EINTR);
849 	}
850 	ethr_mutex_unlock(&dt_mutex);
851 
852 	print_line("dt_count = %d", dt_count);
853     }
854     do_sleep(1);
855 }
856 
857 
858 
859 /*
860  * The max threads test case.
861  *
862  * Tests
863  */
864 #define MTT_TIMES 10
865 #define MTT_HARD_LIMIT (80000)
866 
867 static int mtt_terminate;
868 static ethr_mutex mtt_mutex;
869 static ethr_cond mtt_cond;
870 static char mtt_string[22*MTT_TIMES]; /* 22 is enough for ", %d" */
871 
872 
mtt_thread(void * unused)873 void *mtt_thread(void *unused)
874 {
875     int res;
876 
877     ethr_mutex_lock(&mtt_mutex);
878 
879     while (!mtt_terminate) {
880 	res = ethr_cond_wait(&mtt_cond, &mtt_mutex);
881 	ASSERT(res == 0 || res == EINTR);
882     }
883 
884     ethr_mutex_unlock(&mtt_mutex);
885 
886     return NULL;
887 }
888 
889 
890 static int
mtt_create_join_threads(void)891 mtt_create_join_threads(void)
892 {
893     int no_tids = 100, ix = 0, res = 0, no_threads;
894     ethr_tid *tids;
895 
896     mtt_terminate = 0;
897 
898     tids = (ethr_tid *) malloc(sizeof(ethr_tid)*no_tids);
899     ASSERT(tids);
900 
901     print_line("Beginning to create threads");
902 
903     while (1) {
904 	if (ix >= no_tids) {
905 	    no_tids += 100;
906 	    if (no_tids > MTT_HARD_LIMIT) {
907 		print_line("Hit the hard limit on number of threads (%d)!",
908 			   MTT_HARD_LIMIT);
909 		break;
910 	    }
911 	    tids = (ethr_tid *) realloc((void *)tids, sizeof(ethr_tid)*no_tids);
912 	    ASSERT(tids);
913 	}
914 	res = ethr_thr_create(&tids[ix], mtt_thread, NULL, NULL);
915 	if (res != 0) {
916 	    break;
917 	}
918 	ix++;
919     }
920 
921     no_threads = ix;
922 
923     print_line("%d = ethr_thr_create()", res);
924     print_line("Number of created threads: %d", no_threads);
925 
926     ethr_mutex_lock(&mtt_mutex);
927 
928     mtt_terminate = 1;
929 
930     ethr_cond_broadcast(&mtt_cond);
931 
932     ethr_mutex_unlock(&mtt_mutex);
933 
934     while (ix) {
935 	res = ethr_thr_join(tids[--ix], NULL);
936 	ASSERT(res == 0);
937     }
938 
939     print_line("All created threads terminated");
940 
941     free((void *) tids);
942 
943     return no_threads;
944 
945 }
946 
947 static void
max_threads_test(void)948 max_threads_test(void)
949 {
950     int no_threads[MTT_TIMES], i, up, down, eq, res;
951     char *str;
952 
953     res = ethr_mutex_init(&mtt_mutex);
954     ASSERT(res == 0);
955     res = ethr_cond_init(&mtt_cond);
956     ASSERT(res == 0);
957 
958     for (i = 0; i < MTT_TIMES; i++) {
959 	no_threads[i] = mtt_create_join_threads();
960     }
961 
962     str = &mtt_string[0];
963     eq = up = down = 0;
964     for (i = 0; i < MTT_TIMES; i++) {
965 	if (i == 0) {
966 	    str += sprintf(str, "%d", no_threads[i]);
967 	    continue;
968 	}
969 
970 	str += sprintf(str, ", %d", no_threads[i]);
971 
972 	if (no_threads[i] < no_threads[i-1])
973 	    down++;
974 	else if (no_threads[i] > no_threads[i-1])
975 	    up++;
976 	else
977 	    eq++;
978     }
979 
980     print_line("Max created threads: %s", mtt_string);
981 
982     /* We fail if the no of threads we are able to create constantly decrease */
983     ASSERT(!down || up || eq);
984 
985     succeed("Max created threads: %s", mtt_string);
986 
987 }
988 
989 /*
990  * The tsd test case.
991  *
992  * Tests thread specific data.
993  */
994 
995 #define TT_THREADS 10
996 static ethr_tsd_key tt_key;
997 
998 static void *
tt_thread(void * arg)999 tt_thread(void *arg)
1000 {
1001     int res = ethr_tsd_set(tt_key, arg);
1002     ASSERT(res == 0);
1003     return ethr_tsd_get(tt_key);
1004 }
1005 
1006 static void
tsd_test(void)1007 tsd_test(void)
1008 {
1009     void *tres;
1010     int i, res;
1011     ethr_tid tid[TT_THREADS];
1012     int values[TT_THREADS];
1013 
1014     res = ethr_tsd_key_create(&tt_key,"tsd_test");
1015     ASSERT(res == 0);
1016 
1017     for (i = 1; i < TT_THREADS; i++) {
1018 	res = ethr_thr_create(&tid[i], tt_thread, (void *) &values[i], NULL);
1019 	ASSERT(res == 0);
1020     }
1021 
1022     tres = tt_thread((void *) &values[0]);
1023     ASSERT(tres == (void *) &values[0]);
1024 
1025     for (i = 1; i < TT_THREADS; i++) {
1026 	res = ethr_thr_join(tid[i], &tres);
1027 	ASSERT(res == 0);
1028 	ASSERT(tres == (void *) &values[i]);
1029     }
1030 
1031     res = ethr_tsd_key_delete(tt_key);
1032     ASSERT(res == 0);
1033 }
1034 
1035 
1036 /*
1037  * The spinlock test case.
1038  *
1039  * Tests spinlocks.
1040  */
1041 
1042 static ethr_spinlock_t st_spinlock;
1043 static int st_data;
1044 
1045 void *
st_thread(void * unused)1046 st_thread(void *unused)
1047 {
1048     print_line("Aux thread tries to lock spinlock");
1049     ethr_spin_lock(&st_spinlock);
1050     print_line("Aux thread locked spinlock");
1051 
1052     ASSERT(st_data == 0);
1053 
1054     st_data = 1;
1055     print_line("Aux thread wrote");
1056 
1057     print_line("Aux thread goes to sleep for 1 second");
1058     do_sleep(1);
1059     print_line("Aux thread woke up");
1060 
1061     ASSERT(st_data == 1);
1062 
1063     ethr_spin_unlock(&st_spinlock);
1064     print_line("Aux thread unlocked spinlock");
1065 
1066     return NULL;
1067 }
1068 
1069 
1070 static void
spinlock_test(void)1071 spinlock_test(void)
1072 {
1073     int res;
1074     ethr_tid tid;
1075 
1076     print_line("Trying to initialize spinlock");
1077     res = ethr_spinlock_init(&st_spinlock);
1078     ASSERT(res == 0);
1079     print_line("Initialized spinlock");
1080 
1081     st_data = 0;
1082 
1083     print_line("Main thread tries to lock spinlock");
1084     ethr_spin_lock(&st_spinlock);
1085     print_line("Main thread locked spinlock");
1086 
1087     ASSERT(st_data == 0);
1088 
1089     print_line("Main thread about to create aux thread");
1090     res = ethr_thr_create(&tid, st_thread, NULL, NULL);
1091     ASSERT(res == 0);
1092     print_line("Main thread created aux thread");
1093 
1094     print_line("Main thread goes to sleep for 1 second");
1095     do_sleep(1);
1096     print_line("Main thread woke up");
1097 
1098     ASSERT(st_data == 0);
1099 
1100     ethr_spin_unlock(&st_spinlock);
1101     print_line("Main thread unlocked spinlock");
1102 
1103     print_line("Main thread goes to sleep for 1 second");
1104     do_sleep(1);
1105     print_line("Main thread woke up");
1106 
1107     print_line("Main thread tries to lock spinlock");
1108     ethr_spin_lock(&st_spinlock);
1109     print_line("Main thread locked spinlock");
1110 
1111     ASSERT(st_data == 1);
1112 
1113     print_line("Main thread goes to sleep for 1 second");
1114     do_sleep(1);
1115     print_line("Main thread woke up");
1116 
1117     ASSERT(st_data == 1);
1118 
1119     ethr_spin_unlock(&st_spinlock);
1120     print_line("Main thread unlocked spinlock");
1121 
1122     res = ethr_thr_join(tid, NULL);
1123     ASSERT(res == 0);
1124     print_line("Main thread joined aux thread");
1125 
1126     res = ethr_spinlock_destroy(&st_spinlock);
1127     ASSERT(res == 0);
1128     print_line("Main thread destroyed spinlock");
1129 
1130 }
1131 
1132 
1133 /*
1134  * The rwspinlock test case.
1135  *
1136  * Tests rwspinlocks.
1137  */
1138 
1139 static ethr_rwlock_t rwst_rwspinlock;
1140 static int rwst_data;
1141 
1142 void *
rwst_thread(void * unused)1143 rwst_thread(void *unused)
1144 {
1145     int data;
1146 
1147     print_line("Aux thread tries to read lock rwspinlock");
1148     ethr_read_lock(&rwst_rwspinlock);
1149     print_line("Aux thread read locked rwspinlock");
1150 
1151     ASSERT(rwst_data == 4711);
1152 
1153     print_line("Aux thread tries to read unlock rwspinlock");
1154     ethr_read_unlock(&rwst_rwspinlock);
1155     print_line("Aux thread read unlocked rwspinlock");
1156 
1157     print_line("Aux thread tries to write lock rwspinlock");
1158     ethr_write_lock(&rwst_rwspinlock);
1159     print_line("Aux thread write locked rwspinlock");
1160 
1161     data = ++rwst_data;
1162     print_line("Aux thread wrote");
1163 
1164     print_line("Aux thread goes to sleep for 1 second");
1165     do_sleep(1);
1166     print_line("Aux thread woke up");
1167 
1168     ASSERT(rwst_data == data);
1169     ++rwst_data;
1170 
1171     print_line("Aux thread tries to write unlock rwspinlock");
1172     ethr_write_unlock(&rwst_rwspinlock);
1173     print_line("Aux thread write unlocked rwspinlock");
1174 
1175     return NULL;
1176 }
1177 
1178 
1179 static void
rwspinlock_test(void)1180 rwspinlock_test(void)
1181 {
1182     int data;
1183     int res;
1184     ethr_tid tid;
1185 
1186     print_line("Trying to initialize rwspinlock");
1187     res = ethr_rwlock_init(&rwst_rwspinlock);
1188     ASSERT(res == 0);
1189     print_line("Initialized rwspinlock");
1190 
1191     rwst_data = 4711;
1192 
1193     print_line("Main thread tries to read lock rwspinlock");
1194     ethr_read_lock(&rwst_rwspinlock);
1195     print_line("Main thread read locked rwspinlock");
1196 
1197     ASSERT(rwst_data == 4711);
1198 
1199     print_line("Main thread about to create aux thread");
1200     res = ethr_thr_create(&tid, rwst_thread, NULL, NULL);
1201     ASSERT(res == 0);
1202     print_line("Main thread created aux thread");
1203 
1204     print_line("Main thread goes to sleep for 1 second");
1205     do_sleep(1);
1206     print_line("Main thread woke up");
1207 
1208     ASSERT(rwst_data == 4711);
1209 
1210     print_line("Main thread tries to read unlock rwspinlock");
1211     ethr_read_unlock(&rwst_rwspinlock);
1212     print_line("Main thread read unlocked rwspinlock");
1213 
1214     print_line("Main thread tries to write lock rwspinlock");
1215     ethr_write_lock(&rwst_rwspinlock);
1216     print_line("Main thread write locked rwspinlock");
1217 
1218     data = ++rwst_data;
1219 
1220     print_line("Main thread goes to sleep for 1 second");
1221     do_sleep(1);
1222     print_line("Main thread woke up");
1223 
1224     ASSERT(rwst_data == data);
1225     ++rwst_data;
1226 
1227     print_line("Main thread tries to write unlock rwspinlock");
1228     ethr_write_unlock(&rwst_rwspinlock);
1229     print_line("Main thread write unlocked rwspinlock");
1230 
1231     res = ethr_thr_join(tid, NULL);
1232     ASSERT(res == 0);
1233     print_line("Main thread joined aux thread");
1234 
1235     res = ethr_rwlock_destroy(&rwst_rwspinlock);
1236     ASSERT(res == 0);
1237     print_line("Main thread destroyed rwspinlock");
1238 
1239 }
1240 
1241 
1242 /*
1243  * The rwmutex test case.
1244  *
1245  * Tests rwmutexes.
1246  */
1247 
1248 static ethr_rwmutex rwmt_rwmutex;
1249 static int rwmt_data;
1250 
1251 void *
rwmt_thread(void * unused)1252 rwmt_thread(void *unused)
1253 {
1254     int data;
1255 
1256     print_line("Aux thread tries to read lock rwmutex");
1257     ethr_rwmutex_rlock(&rwmt_rwmutex);
1258     print_line("Aux thread read locked rwmutex");
1259 
1260     ASSERT(rwmt_data == 4711);
1261 
1262     print_line("Aux thread tries to read unlock rwmutex");
1263     ethr_rwmutex_runlock(&rwmt_rwmutex);
1264     print_line("Aux thread read unlocked rwmutex");
1265 
1266     print_line("Aux thread tries to write lock rwmutex");
1267     ethr_rwmutex_rwlock(&rwmt_rwmutex);
1268     print_line("Aux thread write locked rwmutex");
1269 
1270     data = ++rwmt_data;
1271     print_line("Aux thread wrote");
1272 
1273     print_line("Aux thread goes to sleep for 1 second");
1274     do_sleep(1);
1275     print_line("Aux thread woke up");
1276 
1277     ASSERT(rwmt_data == data);
1278     ++rwmt_data;
1279 
1280     print_line("Aux thread tries to write unlock rwmutex");
1281     ethr_rwmutex_rwunlock(&rwmt_rwmutex);
1282     print_line("Aux thread write unlocked rwmutex");
1283 
1284     return NULL;
1285 }
1286 
1287 
1288 static void
rwmutex_test(void)1289 rwmutex_test(void)
1290 {
1291     int data;
1292     int res;
1293     ethr_tid tid;
1294 
1295     print_line("Trying to initialize rwmutex");
1296     res = ethr_rwmutex_init(&rwmt_rwmutex);
1297     ASSERT(res == 0);
1298     print_line("Initialized rwmutex");
1299 
1300     rwmt_data = 4711;
1301 
1302     print_line("Main thread tries to read lock rwmutex");
1303     ethr_rwmutex_rlock(&rwmt_rwmutex);
1304     print_line("Main thread read locked rwmutex");
1305 
1306     ASSERT(rwmt_data == 4711);
1307 
1308     print_line("Main thread about to create aux thread");
1309     res = ethr_thr_create(&tid, rwmt_thread, NULL, NULL);
1310     ASSERT(res == 0);
1311     print_line("Main thread created aux thread");
1312 
1313     print_line("Main thread goes to sleep for 1 second");
1314     do_sleep(1);
1315     print_line("Main thread woke up");
1316 
1317     ASSERT(rwmt_data == 4711);
1318 
1319     print_line("Main thread tries to read unlock rwmutex");
1320     ethr_rwmutex_runlock(&rwmt_rwmutex);
1321     print_line("Main thread read unlocked rwmutex");
1322 
1323     print_line("Main thread tries to write lock rwmutex");
1324     ethr_rwmutex_rwlock(&rwmt_rwmutex);
1325     print_line("Main thread write locked rwmutex");
1326 
1327     data = ++rwmt_data;
1328 
1329     print_line("Main thread goes to sleep for 1 second");
1330     do_sleep(1);
1331     print_line("Main thread woke up");
1332 
1333     ASSERT(rwmt_data == data);
1334     ++rwmt_data;
1335 
1336     print_line("Main thread tries to write unlock rwmutex");
1337     ethr_rwmutex_rwunlock(&rwmt_rwmutex);
1338     print_line("Main thread write unlocked rwmutex");
1339 
1340     res = ethr_thr_join(tid, NULL);
1341     ASSERT(res == 0);
1342     print_line("Main thread joined aux thread");
1343 
1344     res = ethr_rwmutex_destroy(&rwmt_rwmutex);
1345     ASSERT(res == 0);
1346     print_line("Main thread destroyed rwmutex");
1347 
1348 }
1349 
1350 /*
1351  * The atomic test case.
1352  *
1353  * Tests atomics.
1354  */
1355 
1356 #define AT_AINT32_MAX 0x7fffffff
1357 #define AT_AINT32_MIN 0x80000000
1358 
1359 #define AT_THREADS 4
1360 #define AT_ITER 10000
1361 
1362 long at_set_val, at_rm_val, at_max_val;
1363 
1364 static ethr_atomic_t at_ready;
1365 static ethr_atomic_t at_go;
1366 static ethr_atomic_t at_done;
1367 static ethr_atomic_t at_data;
1368 
1369 #define AT_TEST_INIT(T, A, B) \
1370 do { \
1371     ethr_ ## A ## _init ## B(&A, 17); \
1372     ASSERT(ethr_ ## A ## _read ## B(&A) == 17); \
1373 } while (0)
1374 
1375 #define AT_TEST_SET(T, A, B) \
1376 do { \
1377     ethr_ ## A ## _set ## B(&A, 4711); \
1378     ASSERT(ethr_ ## A ## _read ## B(&A) == 4711); \
1379 } while (0)
1380 
1381 #define AT_TEST_XCHG(T, A, B) \
1382 do { \
1383     ethr_ ## A ## _set ## B(&A, 4711); \
1384     ASSERT(ethr_ ## A ## _xchg ## B(&A, 17) == 4711); \
1385     ASSERT(ethr_ ## A ## _read ## B(&A) == 17); \
1386 } while (0)
1387 
1388 #define AT_TEST_CMPXCHG(T, A, B) \
1389 do { \
1390     ethr_ ## A ## _set ## B(&A, 4711); \
1391     ASSERT(ethr_ ## A ## _cmpxchg ## B(&A, 17, 33) == 4711); \
1392     ASSERT(ethr_ ## A ## _read ## B(&A) == 4711); \
1393     ASSERT(ethr_ ## A ## _cmpxchg ## B(&A, 17, 4711) == 4711); \
1394     ASSERT(ethr_ ## A ## _read ## B(&A) == 17); \
1395 } while (0)
1396 
1397 #define AT_TEST_ADD_READ(T, A, B) \
1398 do { \
1399     T var_ = AT_AINT32_MAX; \
1400     var_ += 4711; \
1401     ethr_ ## A ## _set ## B(&A, AT_AINT32_MAX); \
1402     ASSERT(ethr_ ## A ## _add_read ## B(&A, 4711) == var_); \
1403     ASSERT(ethr_ ## A ## _read ## B(&A) == var_); \
1404     var_ = AT_AINT32_MIN; \
1405     var_ -= 4711; \
1406     ethr_ ## A ## _set ## B(&A, AT_AINT32_MIN); \
1407     ASSERT(ethr_ ## A ## _add_read ## B(&A, -4711) == var_); \
1408     ASSERT(ethr_ ## A ## _read ## B(&A) == var_); \
1409     ethr_ ## A ## _set ## B(&A, 4711); \
1410     ASSERT(ethr_ ## A ## _add_read ## B(&A, 10) == 4721); \
1411     ASSERT(ethr_ ## A ## _read ## B(&A) == 4721); \
1412 } while (0)
1413 
1414 #define AT_TEST_ADD(T, A, B) \
1415 do { \
1416     T var_ = AT_AINT32_MAX; \
1417     var_ += 4711; \
1418     ethr_ ## A ## _set ## B(&A, AT_AINT32_MAX); \
1419     ethr_ ## A ## _add ## B(&A, 4711); \
1420     ASSERT(ethr_ ## A ## _read ## B(&A) == var_); \
1421     var_ = AT_AINT32_MIN; \
1422     var_ -= 4711; \
1423     ethr_ ## A ## _set ## B(&A, AT_AINT32_MIN); \
1424     ethr_ ## A ## _add ## B(&A, -4711); \
1425     ASSERT(ethr_ ## A ## _read ## B(&A) == var_); \
1426     ethr_ ## A ## _set ## B(&A, 11); \
1427     ethr_ ## A ## _add ## B(&A, 4700); \
1428     ASSERT(ethr_ ## A ## _read ## B(&A) == 4711); \
1429 } while (0)
1430 
1431 #define AT_TEST_INC_READ(T, A, B) \
1432 do { \
1433     T var_ = AT_AINT32_MAX; \
1434     var_++; \
1435     ethr_ ## A ## _set ## B(&A, AT_AINT32_MAX); \
1436     ASSERT(ethr_ ## A ## _inc_read ## B(&A) == var_); \
1437     ASSERT(ethr_ ## A ## _read ## B(&A) == var_); \
1438     ethr_ ## A ## _set ## B(&A, 4710); \
1439     ASSERT(ethr_ ## A ## _inc_read ## B(&A) == 4711); \
1440     ASSERT(ethr_ ## A ## _read ## B(&A) == 4711); \
1441 } while (0)
1442 
1443 #define AT_TEST_DEC_READ(T, A, B) \
1444 do { \
1445     T var_ = AT_AINT32_MIN; \
1446     var_--; \
1447     ethr_ ## A ## _set ## B(&A, AT_AINT32_MIN); \
1448     ASSERT(ethr_ ## A ## _dec_read ## B(&A) == var_); \
1449     ASSERT(ethr_ ## A ## _read ## B(&A) == var_); \
1450     ethr_ ## A ## _set ## B(&A, 17); \
1451     ASSERT(ethr_ ## A ## _dec_read ## B(&A) == 16); \
1452     ASSERT(ethr_ ## A ## _read ## B(&A) == 16); \
1453 } while (0)
1454 
1455 
1456 #define AT_TEST_INC(T, A, B) \
1457 do { \
1458     T var_ = AT_AINT32_MAX; \
1459     var_++; \
1460     ethr_ ## A ## _set ## B(&A, AT_AINT32_MAX); \
1461     ethr_ ## A ## _inc ## B(&A); \
1462     ASSERT(ethr_ ## A ## _read ## B(&A) == var_); \
1463     ethr_ ## A ## _set ## B(&A, 4710); \
1464     ethr_ ## A ## _inc ## B(&A); \
1465     ASSERT(ethr_ ## A ## _read ## B(&A) == 4711); \
1466 } while (0)
1467 
1468 #define AT_TEST_DEC(T, A, B) \
1469 do { \
1470     T var_ = AT_AINT32_MIN; \
1471     var_--; \
1472     ethr_ ## A ## _set ## B(&A, AT_AINT32_MIN); \
1473     ethr_ ## A ## _dec ## B(&A); \
1474     ASSERT(ethr_ ## A ## _read ## B(&A) == var_); \
1475     ethr_ ## A ## _set ## B(&A, 17); \
1476     ethr_ ## A ## _dec ## B(&A); \
1477     ASSERT(ethr_ ## A ## _read ## B(&A) == 16); \
1478 } while (0)
1479 
1480 #define AT_TEST_READ_BAND(T, A, B) \
1481 do { \
1482     ethr_ ## A ## _set ## B(&A, 0x13131313); \
1483     ASSERT(ethr_ ## A ## _read_band ## B(&A, 0x31313131) == 0x13131313); \
1484     ASSERT(ethr_ ## A ## _read ## B(&A) == 0x11111111); \
1485 } while (0)
1486 
1487 #define AT_TEST_READ_BOR(T, A, B) \
1488 do { \
1489     ethr_ ## A ## _set ## B(&A, 0x11111111); \
1490     ASSERT(ethr_ ## A ## _read_bor ## B(&A, 0x23232323) == 0x11111111); \
1491     ASSERT(ethr_ ## A ## _read ## B(&A) == 0x33333333); \
1492 } while (0)
1493 
1494 ethr_atomic32_t atomic32;
1495 ethr_atomic_t atomic;
1496 ethr_dw_atomic_t dw_atomic;
1497 
1498 static void
atomic_basic_test(void)1499 atomic_basic_test(void)
1500 {
1501     /*
1502      * Verify that each op does what it is expected
1503      * to do for at least one input.
1504      */
1505 
1506     print_line("AT_AINT32_MAX=%d",AT_AINT32_MAX);
1507     print_line("AT_AINT32_MIN=%d",AT_AINT32_MIN);
1508 
1509     AT_TEST_INIT(ethr_sint32_t, atomic32, );
1510     AT_TEST_SET(ethr_sint32_t, atomic32, );
1511     AT_TEST_XCHG(ethr_sint32_t, atomic32, );
1512     AT_TEST_CMPXCHG(ethr_sint32_t, atomic32, );
1513     AT_TEST_ADD_READ(ethr_sint32_t, atomic32, );
1514     AT_TEST_ADD(ethr_sint32_t, atomic32, );
1515     AT_TEST_INC_READ(ethr_sint32_t, atomic32, );
1516     AT_TEST_DEC_READ(ethr_sint32_t, atomic32, );
1517     AT_TEST_INC(ethr_sint32_t, atomic32, );
1518     AT_TEST_DEC(ethr_sint32_t, atomic32, );
1519     AT_TEST_READ_BAND(ethr_sint32_t, atomic32, );
1520     AT_TEST_READ_BOR(ethr_sint32_t, atomic32, );
1521 
1522     AT_TEST_INIT(ethr_sint32_t, atomic32, _acqb);
1523     AT_TEST_SET(ethr_sint32_t, atomic32, _acqb);
1524     AT_TEST_XCHG(ethr_sint32_t, atomic32, _acqb);
1525     AT_TEST_CMPXCHG(ethr_sint32_t, atomic32, _acqb);
1526     AT_TEST_ADD_READ(ethr_sint32_t, atomic32, _acqb);
1527     AT_TEST_ADD(ethr_sint32_t, atomic32, _acqb);
1528     AT_TEST_INC_READ(ethr_sint32_t, atomic32, _acqb);
1529     AT_TEST_DEC_READ(ethr_sint32_t, atomic32, _acqb);
1530     AT_TEST_INC(ethr_sint32_t, atomic32, _acqb);
1531     AT_TEST_DEC(ethr_sint32_t, atomic32, _acqb);
1532     AT_TEST_READ_BAND(ethr_sint32_t, atomic32, _acqb);
1533     AT_TEST_READ_BOR(ethr_sint32_t, atomic32, _acqb);
1534 
1535     AT_TEST_INIT(ethr_sint32_t, atomic32, _relb);
1536     AT_TEST_SET(ethr_sint32_t, atomic32, _relb);
1537     AT_TEST_XCHG(ethr_sint32_t, atomic32, _relb);
1538     AT_TEST_CMPXCHG(ethr_sint32_t, atomic32, _relb);
1539     AT_TEST_ADD_READ(ethr_sint32_t, atomic32, _relb);
1540     AT_TEST_ADD(ethr_sint32_t, atomic32, _relb);
1541     AT_TEST_INC_READ(ethr_sint32_t, atomic32, _relb);
1542     AT_TEST_DEC_READ(ethr_sint32_t, atomic32, _relb);
1543     AT_TEST_INC(ethr_sint32_t, atomic32, _relb);
1544     AT_TEST_DEC(ethr_sint32_t, atomic32, _relb);
1545     AT_TEST_READ_BAND(ethr_sint32_t, atomic32, _relb);
1546     AT_TEST_READ_BOR(ethr_sint32_t, atomic32, _relb);
1547 
1548     AT_TEST_INIT(ethr_sint32_t, atomic32, _rb);
1549     AT_TEST_SET(ethr_sint32_t, atomic32, _rb);
1550     AT_TEST_XCHG(ethr_sint32_t, atomic32, _rb);
1551     AT_TEST_CMPXCHG(ethr_sint32_t, atomic32, _rb);
1552     AT_TEST_ADD_READ(ethr_sint32_t, atomic32, _rb);
1553     AT_TEST_ADD(ethr_sint32_t, atomic32, _rb);
1554     AT_TEST_INC_READ(ethr_sint32_t, atomic32, _rb);
1555     AT_TEST_DEC_READ(ethr_sint32_t, atomic32, _rb);
1556     AT_TEST_INC(ethr_sint32_t, atomic32, _rb);
1557     AT_TEST_DEC(ethr_sint32_t, atomic32, _rb);
1558     AT_TEST_READ_BAND(ethr_sint32_t, atomic32, _rb);
1559     AT_TEST_READ_BOR(ethr_sint32_t, atomic32, _rb);
1560 
1561     AT_TEST_INIT(ethr_sint32_t, atomic32, _wb);
1562     AT_TEST_SET(ethr_sint32_t, atomic32, _wb);
1563     AT_TEST_XCHG(ethr_sint32_t, atomic32, _wb);
1564     AT_TEST_CMPXCHG(ethr_sint32_t, atomic32, _wb);
1565     AT_TEST_ADD_READ(ethr_sint32_t, atomic32, _wb);
1566     AT_TEST_ADD(ethr_sint32_t, atomic32, _wb);
1567     AT_TEST_INC_READ(ethr_sint32_t, atomic32, _wb);
1568     AT_TEST_DEC_READ(ethr_sint32_t, atomic32, _wb);
1569     AT_TEST_INC(ethr_sint32_t, atomic32, _wb);
1570     AT_TEST_DEC(ethr_sint32_t, atomic32, _wb);
1571     AT_TEST_READ_BAND(ethr_sint32_t, atomic32, _wb);
1572     AT_TEST_READ_BOR(ethr_sint32_t, atomic32, _wb);
1573 
1574     AT_TEST_INIT(ethr_sint32_t, atomic32, _mb);
1575     AT_TEST_SET(ethr_sint32_t, atomic32, _mb);
1576     AT_TEST_XCHG(ethr_sint32_t, atomic32, _mb);
1577     AT_TEST_CMPXCHG(ethr_sint32_t, atomic32, _mb);
1578     AT_TEST_ADD_READ(ethr_sint32_t, atomic32, _mb);
1579     AT_TEST_ADD(ethr_sint32_t, atomic32, _mb);
1580     AT_TEST_INC_READ(ethr_sint32_t, atomic32, _mb);
1581     AT_TEST_DEC_READ(ethr_sint32_t, atomic32, _mb);
1582     AT_TEST_INC(ethr_sint32_t, atomic32, _mb);
1583     AT_TEST_DEC(ethr_sint32_t, atomic32, _mb);
1584     AT_TEST_READ_BAND(ethr_sint32_t, atomic32, _mb);
1585     AT_TEST_READ_BOR(ethr_sint32_t, atomic32, _mb);
1586 
1587     AT_TEST_INIT(ethr_sint_t, atomic, );
1588     AT_TEST_SET(ethr_sint_t, atomic, );
1589     AT_TEST_XCHG(ethr_sint_t, atomic, );
1590     AT_TEST_CMPXCHG(ethr_sint_t, atomic, );
1591     AT_TEST_ADD_READ(ethr_sint_t, atomic, );
1592     AT_TEST_ADD(ethr_sint_t, atomic, );
1593     AT_TEST_INC_READ(ethr_sint_t, atomic, );
1594     AT_TEST_DEC_READ(ethr_sint_t, atomic, );
1595     AT_TEST_INC(ethr_sint_t, atomic, );
1596     AT_TEST_DEC(ethr_sint_t, atomic, );
1597     AT_TEST_READ_BAND(ethr_sint_t, atomic, );
1598     AT_TEST_READ_BOR(ethr_sint_t, atomic, );
1599 
1600     AT_TEST_INIT(ethr_sint_t, atomic, _acqb);
1601     AT_TEST_SET(ethr_sint_t, atomic, _acqb);
1602     AT_TEST_XCHG(ethr_sint_t, atomic, _acqb);
1603     AT_TEST_CMPXCHG(ethr_sint_t, atomic, _acqb);
1604     AT_TEST_ADD_READ(ethr_sint_t, atomic, _acqb);
1605     AT_TEST_ADD(ethr_sint_t, atomic, _acqb);
1606     AT_TEST_INC_READ(ethr_sint_t, atomic, _acqb);
1607     AT_TEST_DEC_READ(ethr_sint_t, atomic, _acqb);
1608     AT_TEST_INC(ethr_sint_t, atomic, _acqb);
1609     AT_TEST_DEC(ethr_sint_t, atomic, _acqb);
1610     AT_TEST_READ_BAND(ethr_sint_t, atomic, _acqb);
1611     AT_TEST_READ_BOR(ethr_sint_t, atomic, _acqb);
1612 
1613     AT_TEST_INIT(ethr_sint_t, atomic, _relb);
1614     AT_TEST_SET(ethr_sint_t, atomic, _relb);
1615     AT_TEST_XCHG(ethr_sint_t, atomic, _relb);
1616     AT_TEST_CMPXCHG(ethr_sint_t, atomic, _relb);
1617     AT_TEST_ADD_READ(ethr_sint_t, atomic, _relb);
1618     AT_TEST_ADD(ethr_sint_t, atomic, _relb);
1619     AT_TEST_INC_READ(ethr_sint_t, atomic, _relb);
1620     AT_TEST_DEC_READ(ethr_sint_t, atomic, _relb);
1621     AT_TEST_INC(ethr_sint_t, atomic, _relb);
1622     AT_TEST_DEC(ethr_sint_t, atomic, _relb);
1623     AT_TEST_READ_BAND(ethr_sint_t, atomic, _relb);
1624     AT_TEST_READ_BOR(ethr_sint_t, atomic, _relb);
1625 
1626     AT_TEST_INIT(ethr_sint_t, atomic, _rb);
1627     AT_TEST_SET(ethr_sint_t, atomic, _rb);
1628     AT_TEST_XCHG(ethr_sint_t, atomic, _rb);
1629     AT_TEST_CMPXCHG(ethr_sint_t, atomic, _rb);
1630     AT_TEST_ADD_READ(ethr_sint_t, atomic, _rb);
1631     AT_TEST_ADD(ethr_sint_t, atomic, _rb);
1632     AT_TEST_INC_READ(ethr_sint_t, atomic, _rb);
1633     AT_TEST_DEC_READ(ethr_sint_t, atomic, _rb);
1634     AT_TEST_INC(ethr_sint_t, atomic, _rb);
1635     AT_TEST_DEC(ethr_sint_t, atomic, _rb);
1636     AT_TEST_READ_BAND(ethr_sint_t, atomic, _rb);
1637     AT_TEST_READ_BOR(ethr_sint_t, atomic, _rb);
1638 
1639     AT_TEST_INIT(ethr_sint_t, atomic, _wb);
1640     AT_TEST_SET(ethr_sint_t, atomic, _wb);
1641     AT_TEST_XCHG(ethr_sint_t, atomic, _wb);
1642     AT_TEST_CMPXCHG(ethr_sint_t, atomic, _wb);
1643     AT_TEST_ADD_READ(ethr_sint_t, atomic, _wb);
1644     AT_TEST_ADD(ethr_sint_t, atomic, _wb);
1645     AT_TEST_INC_READ(ethr_sint_t, atomic, _wb);
1646     AT_TEST_DEC_READ(ethr_sint_t, atomic, _wb);
1647     AT_TEST_INC(ethr_sint_t, atomic, _wb);
1648     AT_TEST_DEC(ethr_sint_t, atomic, _wb);
1649     AT_TEST_READ_BAND(ethr_sint_t, atomic, _wb);
1650     AT_TEST_READ_BOR(ethr_sint_t, atomic, _wb);
1651 
1652     AT_TEST_INIT(ethr_sint_t, atomic, _mb);
1653     AT_TEST_SET(ethr_sint_t, atomic, _mb);
1654     AT_TEST_XCHG(ethr_sint_t, atomic, _mb);
1655     AT_TEST_CMPXCHG(ethr_sint_t, atomic, _mb);
1656     AT_TEST_ADD_READ(ethr_sint_t, atomic, _mb);
1657     AT_TEST_ADD(ethr_sint_t, atomic, _mb);
1658     AT_TEST_INC_READ(ethr_sint_t, atomic, _mb);
1659     AT_TEST_DEC_READ(ethr_sint_t, atomic, _mb);
1660     AT_TEST_INC(ethr_sint_t, atomic, _mb);
1661     AT_TEST_DEC(ethr_sint_t, atomic, _mb);
1662     AT_TEST_READ_BAND(ethr_sint_t, atomic, _mb);
1663     AT_TEST_READ_BOR(ethr_sint_t, atomic, _mb);
1664 
1665     /* Double word */
1666     {
1667 	ethr_dw_sint_t dw0, dw1;
1668 	dw0.sint[0] = 4711;
1669 	dw0.sint[1] = 4712;
1670 
1671 	/* init */
1672 	ethr_dw_atomic_init(&dw_atomic, &dw0);
1673 	ethr_dw_atomic_read(&dw_atomic, &dw1);
1674 	ETHR_ASSERT(dw1.sint[0] == 4711);
1675 	ETHR_ASSERT(dw1.sint[1] == 4712);
1676 
1677 	/* set */
1678 	dw0.sint[0] = 42;
1679 	dw0.sint[1] = ~((ethr_sint_t) 0);
1680 	ethr_dw_atomic_set(&dw_atomic, &dw0);
1681 	ethr_dw_atomic_read(&dw_atomic, &dw1);
1682 	ASSERT(dw1.sint[0] == 42);
1683 	ASSERT(dw1.sint[1] == ~((ethr_sint_t) 0));
1684 
1685 	/* cmpxchg */
1686 	dw0.sint[0] = 17;
1687 	dw0.sint[1] = 18;
1688 	dw1.sint[0] = 19;
1689 	dw1.sint[1] = 20;
1690 	ASSERT(!ethr_dw_atomic_cmpxchg(&dw_atomic, &dw1, &dw0));
1691 	ethr_dw_atomic_read(&dw_atomic, &dw0);
1692 	ASSERT(dw0.sint[0] == 42);
1693 	ASSERT(dw0.sint[1] == ~((ethr_sint_t) 0));
1694 
1695 	ASSERT(ethr_dw_atomic_cmpxchg(&dw_atomic, &dw1, &dw0));
1696 
1697 	ethr_dw_atomic_read(&dw_atomic, &dw0);
1698 	ASSERT(dw0.sint[0] == 19);
1699 	ASSERT(dw0.sint[1] == 20);
1700     }
1701 }
1702 
1703 
1704 #define AT_DW_MIN 12
1705 #define AT_DW_MAX 42
1706 #define AT_DW_THREADS (AT_DW_MAX - AT_DW_MIN + 1)
1707 
1708 #define AT_DW_LOOPS 200000
1709 #define AT_DW_R_LOOPS 10
1710 
1711 ethr_dw_atomic_t at_dw_atomic;
1712 
1713 void
at_dw_valid(ethr_dw_sint_t * dw)1714 at_dw_valid(ethr_dw_sint_t *dw)
1715 {
1716     int i;
1717     char c;
1718     char *cp;
1719 
1720     ASSERT(dw->sint[0] == dw->sint[1]);
1721 
1722     cp = (char *) &dw->sint[0];
1723     c = cp[0];
1724 
1725     ASSERT(AT_DW_MIN <= c && c <= AT_DW_MAX);
1726 
1727     for (i = 0; i < sizeof(ethr_sint_t); i++)
1728 	ASSERT(c == cp[i]);
1729 }
1730 
1731 void *
at_dw_thr(void * vval)1732 at_dw_thr(void *vval)
1733 {
1734     int l, r;
1735     ethr_sint_t val = (ethr_sint_t) vval;
1736     ethr_dw_sint_t dw;
1737     ethr_dw_sint_t my_dw;
1738 
1739     my_dw.sint[0] = val;
1740     my_dw.sint[1] = val;
1741 
1742     ethr_dw_atomic_set(&at_dw_atomic, &my_dw);
1743     for (l = 0; l < AT_DW_LOOPS; l++) {
1744 	for (r = 0; r < AT_DW_R_LOOPS; r++) {
1745 	    ethr_dw_atomic_read(&at_dw_atomic, &dw);
1746 	    at_dw_valid(&dw);
1747 	}
1748 	ethr_dw_atomic_set(&at_dw_atomic, &my_dw);
1749 	for (r = 0; r < AT_DW_R_LOOPS; r++) {
1750 	    ethr_dw_atomic_read(&at_dw_atomic, &dw);
1751 	    at_dw_valid(&dw);
1752 	}
1753 	dw.sint[0] = 0;
1754 	dw.sint[1] = 0;
1755 	while (1) {
1756 	    if (ethr_dw_atomic_cmpxchg(&at_dw_atomic, &my_dw, &dw))
1757 		break;
1758 	}
1759     }
1760 }
1761 
1762 static void
dw_atomic_massage_test(void)1763 dw_atomic_massage_test(void)
1764 {
1765     int i, res;
1766     ethr_tid tid[AT_DW_THREADS];
1767     ethr_thr_opts thr_opts = ETHR_THR_OPTS_DEFAULT_INITER;
1768     ethr_dw_sint_t dw;
1769 
1770     dw.sint[0] = dw.sint[1] = 0;
1771 
1772     ethr_dw_atomic_init(&at_dw_atomic, &dw);
1773 
1774     for (i = AT_DW_MIN; i <= AT_DW_MAX; i++) {
1775 	ethr_sint_t val;
1776 	memset(&val, i, sizeof(ethr_sint_t));
1777 	res = ethr_thr_create(&tid[i-AT_DW_MIN], at_dw_thr, (void *) val, &thr_opts);
1778 	ASSERT(res == 0);
1779     }
1780     for (i = AT_DW_MIN; i <= AT_DW_MAX; i++) {
1781 	res = ethr_thr_join(tid[i-AT_DW_MIN], NULL);
1782 	ASSERT(res == 0);
1783     }
1784 }
1785 
1786 void *
at_thread(void * unused)1787 at_thread(void *unused)
1788 {
1789     int i;
1790     long val, go;
1791 
1792     val = ethr_atomic_inc_read(&at_ready);
1793     ASSERT(val > 0);
1794     ASSERT(val <= AT_THREADS);
1795 
1796     do {
1797 	go = ethr_atomic_read(&at_go);
1798     } while (!go);
1799 
1800     for (i = 0; i < AT_ITER; i++) {
1801 	val = ethr_atomic_read_bor(&at_data, at_set_val);
1802 	ASSERT(val >= (i == 0 ? 0 : at_set_val) + (long) 4711);
1803 	ASSERT(val <= at_max_val);
1804 
1805 	val = ethr_atomic_read_band(&at_data, ~at_rm_val);
1806 	ASSERT(val >= at_set_val + (long) 4711);
1807 	ASSERT(val <= at_max_val);
1808 
1809 	val = ethr_atomic_read(&at_data);
1810 	ASSERT(val >= at_set_val + (long) 4711);
1811 	ASSERT(val <= at_max_val);
1812 
1813 	val = ethr_atomic_inc_read(&at_data);
1814 	ASSERT(val > at_set_val + (long) 4711);
1815 	ASSERT(val <= at_max_val);
1816 
1817 	val = ethr_atomic_dec_read(&at_data);
1818 	ASSERT(val >= at_set_val + (long) 4711);
1819 	ASSERT(val <= at_max_val);
1820 
1821 	ethr_atomic_inc(&at_data);
1822 
1823 	ethr_atomic_dec(&at_data);
1824 
1825 	val = ethr_atomic_add_read(&at_data, (long) 4711);
1826 	ASSERT(val >= at_set_val + (long) 2*4711);
1827 	ASSERT(val <= at_max_val);
1828 
1829 	ethr_atomic_add(&at_data, (long) -4711);
1830 	ASSERT(val >= at_set_val + (long) 4711);
1831 	ASSERT(val <= at_max_val);
1832     }
1833 
1834     ethr_atomic_inc(&at_done);
1835     return NULL;
1836 }
1837 
1838 static void
atomic_test(void)1839 atomic_test(void)
1840 {
1841     long data_init, data_final, val;
1842     int res, i;
1843     ethr_tid tid[AT_THREADS];
1844     ethr_thr_opts thr_opts = ETHR_THR_OPTS_DEFAULT_INITER;
1845 
1846     atomic_basic_test();
1847 
1848 #if ETHR_SIZEOF_PTR > 4
1849 	at_rm_val = ((long) 1) << 57;
1850 	at_set_val = ((long) 1) << 60;
1851 #else
1852 	at_rm_val = ((long) 1) << 27;
1853 	at_set_val = ((long) 1) << 30;
1854 #endif
1855 
1856     at_max_val = at_set_val + at_rm_val + ((long) AT_THREADS + 1) * 4711;
1857     data_init = at_rm_val + (long) 4711;
1858     data_final = at_set_val + (long) 4711;
1859 
1860     thr_opts.detached = 1;
1861 
1862     print_line("Initializing");
1863     ethr_atomic_init(&at_ready, 0);
1864     ethr_atomic_init(&at_go, 0);
1865     ethr_atomic_init(&at_done, data_init);
1866     ethr_atomic_init(&at_data, data_init);
1867 
1868     val = ethr_atomic_read(&at_data);
1869     ASSERT(val == data_init);
1870     ethr_atomic_set(&at_done, 0);
1871     val = ethr_atomic_read(&at_done);
1872     ASSERT(val == 0);
1873 
1874     print_line("Creating threads");
1875     for (i = 0; i < AT_THREADS; i++) {
1876 	res = ethr_thr_create(&tid[i], at_thread, NULL, &thr_opts);
1877 	ASSERT(res == 0);
1878     }
1879 
1880     print_line("Waiting for threads to ready up");
1881     do {
1882 	val = ethr_atomic_read(&at_ready);
1883 	ASSERT(val >= 0);
1884 	ASSERT(val <= AT_THREADS);
1885     } while (val != AT_THREADS);
1886 
1887     print_line("Letting threads loose");
1888     val = ethr_atomic_xchg(&at_go, 17);
1889     ASSERT(val == 0);
1890     val = ethr_atomic_read(&at_go);
1891     ASSERT(val == 17);
1892 
1893 
1894     print_line("Waiting for threads to finish");
1895     do {
1896 	val = ethr_atomic_read(&at_done);
1897 	ASSERT(val >= 0);
1898 	ASSERT(val <= AT_THREADS);
1899     } while (val != AT_THREADS);
1900 
1901     print_line("Checking result");
1902     val = ethr_atomic_read(&at_data);
1903     ASSERT(res == 0);
1904     ASSERT(val == data_final);
1905     print_line("Result ok");
1906 
1907 }
1908 
1909 
1910 #endif /* #ifndef ETHR_NO_THREAD_LIB */
1911 
1912 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1913  * The dispatcher                                                            *
1914 \*                                                                           */
1915 
1916 int
main(int argc,char * argv[])1917 main(int argc, char *argv[])
1918 {
1919     if (argc < 2)
1920 	fail("To few arguments for test case");
1921 
1922 #ifndef ETHR_NO_THREAD_LIB
1923     {
1924 	char *testcase;
1925 
1926 	send_my_pid();
1927 
1928 	testcase = argv[1];
1929 
1930 	if (ethr_init(NULL) != 0 || ethr_late_init(NULL) != 0)
1931 	    fail("Failed to initialize the ethread library");
1932 
1933 	if (strcmp(testcase, "create_join_thread") == 0)
1934 	    create_join_thread_test();
1935 	else if (strcmp(testcase, "equal_tids") == 0)
1936 	    equal_tids_test();
1937 	else if (strcmp(testcase, "mutex") == 0)
1938 	    mutex_test();
1939 	else if (strcmp(testcase, "try_lock_mutex") == 0)
1940 	    try_lock_mutex_test();
1941 	else if (strcmp(testcase, "cond_wait") == 0)
1942 	    cond_wait_test();
1943 	else if (strcmp(testcase, "broadcast") == 0)
1944 	    broadcast_test();
1945 	else if (strcmp(testcase, "detached_thread") == 0)
1946 	    detached_thread_test();
1947 	else if (strcmp(testcase, "max_threads") == 0)
1948 	    max_threads_test();
1949 	else if (strcmp(testcase, "tsd") == 0)
1950 	    tsd_test();
1951 	else if (strcmp(testcase, "spinlock") == 0)
1952 	    spinlock_test();
1953 	else if (strcmp(testcase, "rwspinlock") == 0)
1954 	    rwspinlock_test();
1955 	else if (strcmp(testcase, "rwmutex") == 0)
1956 	    rwmutex_test();
1957 	else if (strcmp(testcase, "atomic") == 0)
1958 	    atomic_test();
1959 	else if (strcmp(testcase, "dw_atomic_massage") == 0)
1960 	    dw_atomic_massage_test();
1961 	else
1962 	    skip("Test case \"%s\" not implemented yet", testcase);
1963 
1964 	succeed(NULL);
1965     }
1966 #else /* #ifndef ETHR_NO_THREAD_LIB */
1967     skip("No ethread library to test");
1968 #endif /* #ifndef ETHR_NO_THREAD_LIB */
1969 
1970     return 0;
1971 }
1972