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