1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 /***********************************************************************
7 ** 1996 - Netscape Communications Corporation
8 **
9 ** Name: cvar2.c
10 **
11 ** Description: Simple test creates several local and global threads;
12 ** half use a single,shared condvar, and the
13 ** other half have their own condvar. The main thread then loops
14 ** notifying them to wakeup.
15 **
16 ** Modification History:
17 ** 14-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
18 ** The debug mode will print all of the printfs associated with this test.
19 ** The regress mode will be the default mode. Since the regress tool limits
20 ** the output to a one line status:PASS or FAIL,all of the printf statements
21 ** have been handled with an if (debug_mode) statement.
22 ***********************************************************************/
23
24 #include "nspr.h"
25 #include "plerror.h"
26 #include "plgetopt.h"
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31
32 int _debug_on = 0;
33 #define DPRINTF(arg) if (_debug_on) printf arg
34
35 #define DEFAULT_COUNT 100
36 #define DEFAULT_THREADS 5
37 PRInt32 count = DEFAULT_COUNT;
38
39 typedef struct threadinfo {
40 PRThread *thread;
41 PRInt32 id;
42 PRBool internal;
43 PRInt32 *tcount;
44 PRLock *lock;
45 PRCondVar *cvar;
46 PRIntervalTime timeout;
47 PRInt32 loops;
48
49 PRLock *exitlock;
50 PRCondVar *exitcvar;
51 PRInt32 *exitcount;
52 } threadinfo;
53
54 /*
55 ** Make exitcount, tcount static. for Win16.
56 */
57 static PRInt32 exitcount=0;
58 static PRInt32 tcount=0;
59
60
61 /* Thread that gets notified; many threads share the same condvar */
62 void PR_CALLBACK
SharedCondVarThread(void * _info)63 SharedCondVarThread(void *_info)
64 {
65 threadinfo *info = (threadinfo *)_info;
66 PRInt32 index;
67
68 for (index=0; index<info->loops; index++) {
69 PR_Lock(info->lock);
70 if (*info->tcount == 0) {
71 PR_WaitCondVar(info->cvar, info->timeout);
72 }
73 #if 0
74 printf("shared thread %ld notified in loop %ld\n", info->id, index);
75 #endif
76 (*info->tcount)--;
77 PR_Unlock(info->lock);
78
79 PR_Lock(info->exitlock);
80 (*info->exitcount)++;
81 PR_NotifyCondVar(info->exitcvar);
82 PR_Unlock(info->exitlock);
83 }
84 #if 0
85 printf("shared thread %ld terminating\n", info->id);
86 #endif
87 }
88
89 /* Thread that gets notified; no other threads use the same condvar */
90 void PR_CALLBACK
PrivateCondVarThread(void * _info)91 PrivateCondVarThread(void *_info)
92 {
93 threadinfo *info = (threadinfo *)_info;
94 PRInt32 index;
95
96 for (index=0; index<info->loops; index++) {
97 PR_Lock(info->lock);
98 if (*info->tcount == 0) {
99 DPRINTF(("PrivateCondVarThread: thread 0x%lx waiting on cvar = 0x%lx\n",
100 PR_GetCurrentThread(), info->cvar));
101 PR_WaitCondVar(info->cvar, info->timeout);
102 }
103 #if 0
104 printf("solo thread %ld notified in loop %ld\n", info->id, index);
105 #endif
106 (*info->tcount)--;
107 PR_Unlock(info->lock);
108
109 PR_Lock(info->exitlock);
110 (*info->exitcount)++;
111 PR_NotifyCondVar(info->exitcvar);
112 DPRINTF(("PrivateCondVarThread: thread 0x%lx notified exitcvar = 0x%lx cnt = %ld\n",
113 PR_GetCurrentThread(), info->exitcvar,(*info->exitcount)));
114 PR_Unlock(info->exitlock);
115 }
116 #if 0
117 printf("solo thread %ld terminating\n", info->id);
118 #endif
119 }
120
121 void
CreateTestThread(threadinfo * info,PRInt32 id,PRLock * lock,PRCondVar * cvar,PRInt32 loops,PRIntervalTime timeout,PRInt32 * tcount,PRLock * exitlock,PRCondVar * exitcvar,PRInt32 * exitcount,PRBool shared,PRThreadScope scope)122 CreateTestThread(threadinfo *info,
123 PRInt32 id,
124 PRLock *lock,
125 PRCondVar *cvar,
126 PRInt32 loops,
127 PRIntervalTime timeout,
128 PRInt32 *tcount,
129 PRLock *exitlock,
130 PRCondVar *exitcvar,
131 PRInt32 *exitcount,
132 PRBool shared,
133 PRThreadScope scope)
134 {
135 info->id = id;
136 info->internal = (shared) ? PR_FALSE : PR_TRUE;
137 info->lock = lock;
138 info->cvar = cvar;
139 info->loops = loops;
140 info->timeout = timeout;
141 info->tcount = tcount;
142 info->exitlock = exitlock;
143 info->exitcvar = exitcvar;
144 info->exitcount = exitcount;
145 info->thread = PR_CreateThread(
146 PR_USER_THREAD,
147 shared?SharedCondVarThread:PrivateCondVarThread,
148 info,
149 PR_PRIORITY_NORMAL,
150 scope,
151 PR_JOINABLE_THREAD,
152 0);
153 if (!info->thread) {
154 PL_PrintError("error creating thread\n");
155 }
156 }
157
158
159 void
CondVarTestSUU(void * _arg)160 CondVarTestSUU(void *_arg)
161 {
162 PRInt32 arg = (PRInt32)_arg;
163 PRInt32 index, loops;
164 threadinfo *list;
165 PRLock *sharedlock;
166 PRCondVar *sharedcvar;
167 PRLock *exitlock;
168 PRCondVar *exitcvar;
169
170 exitcount=0;
171 tcount=0;
172 list = (threadinfo *)PR_MALLOC(sizeof(threadinfo) * (arg * 4));
173
174 sharedlock = PR_NewLock();
175 sharedcvar = PR_NewCondVar(sharedlock);
176 exitlock = PR_NewLock();
177 exitcvar = PR_NewCondVar(exitlock);
178
179 /* Create the threads */
180 for(index=0; index<arg; ) {
181 CreateTestThread(&list[index],
182 index,
183 sharedlock,
184 sharedcvar,
185 count,
186 PR_INTERVAL_NO_TIMEOUT,
187 &tcount,
188 exitlock,
189 exitcvar,
190 &exitcount,
191 PR_TRUE,
192 PR_LOCAL_THREAD);
193 index++;
194 DPRINTF(("CondVarTestSUU: created thread 0x%lx\n",list[index].thread));
195 }
196
197 for (loops = 0; loops < count; loops++) {
198 /* Notify the threads */
199 for(index=0; index<(arg); index++) {
200 PR_Lock(list[index].lock);
201 (*list[index].tcount)++;
202 PR_NotifyCondVar(list[index].cvar);
203 PR_Unlock(list[index].lock);
204 DPRINTF(("PrivateCondVarThread: thread 0x%lx notified cvar = 0x%lx\n",
205 PR_GetCurrentThread(), list[index].cvar));
206 }
207
208 /* Wait for threads to finish */
209 PR_Lock(exitlock);
210 while(exitcount < arg) {
211 PR_WaitCondVar(exitcvar, PR_SecondsToInterval(60));
212 }
213 PR_ASSERT(exitcount >= arg);
214 exitcount -= arg;
215 PR_Unlock(exitlock);
216 }
217
218 /* Join all the threads */
219 for(index=0; index<(arg); index++) {
220 PR_JoinThread(list[index].thread);
221 }
222
223 PR_DestroyCondVar(sharedcvar);
224 PR_DestroyLock(sharedlock);
225 PR_DestroyCondVar(exitcvar);
226 PR_DestroyLock(exitlock);
227
228 PR_DELETE(list);
229 }
230
231 void
CondVarTestSUK(void * _arg)232 CondVarTestSUK(void *_arg)
233 {
234 PRInt32 arg = (PRInt32)_arg;
235 PRInt32 index, loops;
236 threadinfo *list;
237 PRLock *sharedlock;
238 PRCondVar *sharedcvar;
239 PRLock *exitlock;
240 PRCondVar *exitcvar;
241 exitcount=0;
242 tcount=0;
243
244 list = (threadinfo *)PR_MALLOC(sizeof(threadinfo) * (arg * 4));
245
246 sharedlock = PR_NewLock();
247 sharedcvar = PR_NewCondVar(sharedlock);
248 exitlock = PR_NewLock();
249 exitcvar = PR_NewCondVar(exitlock);
250
251 /* Create the threads */
252 for(index=0; index<arg; ) {
253 CreateTestThread(&list[index],
254 index,
255 sharedlock,
256 sharedcvar,
257 count,
258 PR_INTERVAL_NO_TIMEOUT,
259 &tcount,
260 exitlock,
261 exitcvar,
262 &exitcount,
263 PR_TRUE,
264 PR_GLOBAL_THREAD);
265 index++;
266 }
267
268 for (loops = 0; loops < count; loops++) {
269 /* Notify the threads */
270 for(index=0; index<(arg); index++) {
271
272 PR_Lock(list[index].lock);
273 (*list[index].tcount)++;
274 PR_NotifyCondVar(list[index].cvar);
275 PR_Unlock(list[index].lock);
276 }
277
278 #if 0
279 printf("wait for threads to be done\n");
280 #endif
281 /* Wait for threads to finish */
282 PR_Lock(exitlock);
283 while(exitcount < arg) {
284 PR_WaitCondVar(exitcvar, PR_SecondsToInterval(60));
285 }
286 PR_ASSERT(exitcount >= arg);
287 exitcount -= arg;
288 PR_Unlock(exitlock);
289 #if 0
290 printf("threads ready\n");
291 #endif
292 }
293
294 /* Join all the threads */
295 for(index=0; index<(arg); index++) {
296 PR_JoinThread(list[index].thread);
297 }
298
299 PR_DestroyCondVar(sharedcvar);
300 PR_DestroyLock(sharedlock);
301 PR_DestroyCondVar(exitcvar);
302 PR_DestroyLock(exitlock);
303
304 PR_DELETE(list);
305 }
306
307 void
CondVarTestPUU(void * _arg)308 CondVarTestPUU(void *_arg)
309 {
310 PRInt32 arg = (PRInt32)_arg;
311 PRInt32 index, loops;
312 threadinfo *list;
313 PRLock *sharedlock;
314 PRCondVar *sharedcvar;
315 PRLock *exitlock;
316 PRCondVar *exitcvar;
317 PRInt32 *tcount, *saved_tcount;
318
319 exitcount=0;
320 list = (threadinfo *)PR_MALLOC(sizeof(threadinfo) * (arg * 4));
321 saved_tcount = tcount = (PRInt32 *)PR_CALLOC(sizeof(*tcount) * (arg * 4));
322
323 sharedlock = PR_NewLock();
324 sharedcvar = PR_NewCondVar(sharedlock);
325 exitlock = PR_NewLock();
326 exitcvar = PR_NewCondVar(exitlock);
327
328 /* Create the threads */
329 for(index=0; index<arg; ) {
330 list[index].lock = PR_NewLock();
331 list[index].cvar = PR_NewCondVar(list[index].lock);
332 CreateTestThread(&list[index],
333 index,
334 list[index].lock,
335 list[index].cvar,
336 count,
337 PR_INTERVAL_NO_TIMEOUT,
338 tcount,
339 exitlock,
340 exitcvar,
341 &exitcount,
342 PR_FALSE,
343 PR_LOCAL_THREAD);
344
345 DPRINTF(("CondVarTestPUU: created thread 0x%lx\n",list[index].thread));
346 index++;
347 tcount++;
348 }
349
350 for (loops = 0; loops < count; loops++) {
351 /* Notify the threads */
352 for(index=0; index<(arg); index++) {
353
354 PR_Lock(list[index].lock);
355 (*list[index].tcount)++;
356 PR_NotifyCondVar(list[index].cvar);
357 PR_Unlock(list[index].lock);
358 }
359
360 PR_Lock(exitlock);
361 /* Wait for threads to finish */
362 while(exitcount < arg) {
363 DPRINTF(("CondVarTestPUU: thread 0x%lx waiting on exitcvar = 0x%lx cnt = %ld\n",
364 PR_GetCurrentThread(), exitcvar, exitcount));
365 PR_WaitCondVar(exitcvar, PR_SecondsToInterval(60));
366 }
367 PR_ASSERT(exitcount >= arg);
368 exitcount -= arg;
369 PR_Unlock(exitlock);
370 }
371
372 /* Join all the threads */
373 for(index=0; index<(arg); index++) {
374 DPRINTF(("CondVarTestPUU: joining thread 0x%lx\n",list[index].thread));
375 PR_JoinThread(list[index].thread);
376 if (list[index].internal) {
377 PR_Lock(list[index].lock);
378 PR_DestroyCondVar(list[index].cvar);
379 PR_Unlock(list[index].lock);
380 PR_DestroyLock(list[index].lock);
381 }
382 }
383
384 PR_DestroyCondVar(sharedcvar);
385 PR_DestroyLock(sharedlock);
386 PR_DestroyCondVar(exitcvar);
387 PR_DestroyLock(exitlock);
388
389 PR_DELETE(list);
390 PR_DELETE(saved_tcount);
391 }
392
393 void
CondVarTestPUK(void * _arg)394 CondVarTestPUK(void *_arg)
395 {
396 PRInt32 arg = (PRInt32)_arg;
397 PRInt32 index, loops;
398 threadinfo *list;
399 PRLock *sharedlock;
400 PRCondVar *sharedcvar;
401 PRLock *exitlock;
402 PRCondVar *exitcvar;
403 PRInt32 *tcount, *saved_tcount;
404
405 exitcount=0;
406 list = (threadinfo *)PR_MALLOC(sizeof(threadinfo) * (arg * 4));
407 saved_tcount = tcount = (PRInt32 *)PR_CALLOC(sizeof(*tcount) * (arg * 4));
408
409 sharedlock = PR_NewLock();
410 sharedcvar = PR_NewCondVar(sharedlock);
411 exitlock = PR_NewLock();
412 exitcvar = PR_NewCondVar(exitlock);
413
414 /* Create the threads */
415 for(index=0; index<arg; ) {
416 list[index].lock = PR_NewLock();
417 list[index].cvar = PR_NewCondVar(list[index].lock);
418 CreateTestThread(&list[index],
419 index,
420 list[index].lock,
421 list[index].cvar,
422 count,
423 PR_INTERVAL_NO_TIMEOUT,
424 tcount,
425 exitlock,
426 exitcvar,
427 &exitcount,
428 PR_FALSE,
429 PR_GLOBAL_THREAD);
430
431 index++;
432 tcount++;
433 }
434
435 for (loops = 0; loops < count; loops++) {
436 /* Notify the threads */
437 for(index=0; index<(arg); index++) {
438
439 PR_Lock(list[index].lock);
440 (*list[index].tcount)++;
441 PR_NotifyCondVar(list[index].cvar);
442 PR_Unlock(list[index].lock);
443 }
444
445 /* Wait for threads to finish */
446 PR_Lock(exitlock);
447 while(exitcount < arg) {
448 PR_WaitCondVar(exitcvar, PR_SecondsToInterval(60));
449 }
450 PR_ASSERT(exitcount >= arg);
451 exitcount -= arg;
452 PR_Unlock(exitlock);
453 }
454
455 /* Join all the threads */
456 for(index=0; index<(arg); index++) {
457 PR_JoinThread(list[index].thread);
458 if (list[index].internal) {
459 PR_Lock(list[index].lock);
460 PR_DestroyCondVar(list[index].cvar);
461 PR_Unlock(list[index].lock);
462 PR_DestroyLock(list[index].lock);
463 }
464 }
465
466 PR_DestroyCondVar(sharedcvar);
467 PR_DestroyLock(sharedlock);
468 PR_DestroyCondVar(exitcvar);
469 PR_DestroyLock(exitlock);
470
471 PR_DELETE(list);
472 PR_DELETE(saved_tcount);
473 }
474
475 void
CondVarTest(void * _arg)476 CondVarTest(void *_arg)
477 {
478 PRInt32 arg = (PRInt32)_arg;
479 PRInt32 index, loops;
480 threadinfo *list;
481 PRLock *sharedlock;
482 PRCondVar *sharedcvar;
483 PRLock *exitlock;
484 PRCondVar *exitcvar;
485 PRInt32 *ptcount, *saved_ptcount;
486
487 exitcount=0;
488 tcount=0;
489 list = (threadinfo *)PR_MALLOC(sizeof(threadinfo) * (arg * 4));
490 saved_ptcount = ptcount = (PRInt32 *)PR_CALLOC(sizeof(*ptcount) * (arg * 4));
491
492 sharedlock = PR_NewLock();
493 sharedcvar = PR_NewCondVar(sharedlock);
494 exitlock = PR_NewLock();
495 exitcvar = PR_NewCondVar(exitlock);
496
497 /* Create the threads */
498 for(index=0; index<arg*4; ) {
499 CreateTestThread(&list[index],
500 index,
501 sharedlock,
502 sharedcvar,
503 count,
504 PR_INTERVAL_NO_TIMEOUT,
505 &tcount,
506 exitlock,
507 exitcvar,
508 &exitcount,
509 PR_TRUE,
510 PR_LOCAL_THREAD);
511
512 index++;
513 CreateTestThread(&list[index],
514 index,
515 sharedlock,
516 sharedcvar,
517 count,
518 PR_INTERVAL_NO_TIMEOUT,
519 &tcount,
520 exitlock,
521 exitcvar,
522 &exitcount,
523 PR_TRUE,
524 PR_GLOBAL_THREAD);
525
526 index++;
527 list[index].lock = PR_NewLock();
528 list[index].cvar = PR_NewCondVar(list[index].lock);
529 CreateTestThread(&list[index],
530 index,
531 list[index].lock,
532 list[index].cvar,
533 count,
534 PR_INTERVAL_NO_TIMEOUT,
535 ptcount,
536 exitlock,
537 exitcvar,
538 &exitcount,
539 PR_FALSE,
540 PR_LOCAL_THREAD);
541 index++;
542 ptcount++;
543 list[index].lock = PR_NewLock();
544 list[index].cvar = PR_NewCondVar(list[index].lock);
545 CreateTestThread(&list[index],
546 index,
547 list[index].lock,
548 list[index].cvar,
549 count,
550 PR_INTERVAL_NO_TIMEOUT,
551 ptcount,
552 exitlock,
553 exitcvar,
554 &exitcount,
555 PR_FALSE,
556 PR_GLOBAL_THREAD);
557
558 index++;
559 ptcount++;
560 }
561
562 for (loops = 0; loops < count; loops++) {
563
564 /* Notify the threads */
565 for(index=0; index<(arg*4); index++) {
566 PR_Lock(list[index].lock);
567 (*list[index].tcount)++;
568 PR_NotifyCondVar(list[index].cvar);
569 PR_Unlock(list[index].lock);
570 }
571
572 #if 0
573 printf("wait for threads done\n");
574 #endif
575
576 /* Wait for threads to finish */
577 PR_Lock(exitlock);
578 while(exitcount < arg*4) {
579 PR_WaitCondVar(exitcvar, PR_SecondsToInterval(60));
580 }
581 PR_ASSERT(exitcount >= arg*4);
582 exitcount -= arg*4;
583 PR_Unlock(exitlock);
584 #if 0
585 printf("threads ready\n");
586 #endif
587 }
588
589 /* Join all the threads */
590 for(index=0; index<(arg*4); index++) {
591 PR_JoinThread(list[index].thread);
592 if (list[index].internal) {
593 PR_Lock(list[index].lock);
594 PR_DestroyCondVar(list[index].cvar);
595 PR_Unlock(list[index].lock);
596 PR_DestroyLock(list[index].lock);
597 }
598 }
599
600 PR_DestroyCondVar(sharedcvar);
601 PR_DestroyLock(sharedlock);
602 PR_DestroyCondVar(exitcvar);
603 PR_DestroyLock(exitlock);
604
605 PR_DELETE(list);
606 PR_DELETE(saved_ptcount);
607 }
608
609 void
CondVarTimeoutTest(void * _arg)610 CondVarTimeoutTest(void *_arg)
611 {
612 PRInt32 arg = (PRInt32)_arg;
613 PRInt32 index, loops;
614 threadinfo *list;
615 PRLock *sharedlock;
616 PRCondVar *sharedcvar;
617 PRLock *exitlock;
618 PRCondVar *exitcvar;
619
620 list = (threadinfo *)PR_MALLOC(sizeof(threadinfo) * (arg * 4));
621
622 sharedlock = PR_NewLock();
623 sharedcvar = PR_NewCondVar(sharedlock);
624 exitlock = PR_NewLock();
625 exitcvar = PR_NewCondVar(exitlock);
626
627 /* Create the threads */
628 for(index=0; index<arg*4; ) {
629 CreateTestThread(&list[index],
630 index,
631 sharedlock,
632 sharedcvar,
633 count,
634 PR_MillisecondsToInterval(50),
635 &tcount,
636 exitlock,
637 exitcvar,
638 &exitcount,
639 PR_TRUE,
640 PR_LOCAL_THREAD);
641 index++;
642 CreateTestThread(&list[index],
643 index,
644 sharedlock,
645 sharedcvar,
646 count,
647 PR_MillisecondsToInterval(50),
648 &tcount,
649 exitlock,
650 exitcvar,
651 &exitcount,
652 PR_TRUE,
653 PR_GLOBAL_THREAD);
654 index++;
655 list[index].lock = PR_NewLock();
656 list[index].cvar = PR_NewCondVar(list[index].lock);
657 CreateTestThread(&list[index],
658 index,
659 list[index].lock,
660 list[index].cvar,
661 count,
662 PR_MillisecondsToInterval(50),
663 &tcount,
664 exitlock,
665 exitcvar,
666 &exitcount,
667 PR_FALSE,
668 PR_LOCAL_THREAD);
669 index++;
670
671 list[index].lock = PR_NewLock();
672 list[index].cvar = PR_NewCondVar(list[index].lock);
673 CreateTestThread(&list[index],
674 index,
675 list[index].lock,
676 list[index].cvar,
677 count,
678 PR_MillisecondsToInterval(50),
679 &tcount,
680 exitlock,
681 exitcvar,
682 &exitcount,
683 PR_FALSE,
684 PR_GLOBAL_THREAD);
685
686 index++;
687 }
688
689 for (loops = 0; loops < count; loops++) {
690
691 /* Wait for threads to finish */
692 PR_Lock(exitlock);
693 while(exitcount < arg*4) {
694 PR_WaitCondVar(exitcvar, PR_SecondsToInterval(60));
695 }
696 PR_ASSERT(exitcount >= arg*4);
697 exitcount -= arg*4;
698 PR_Unlock(exitlock);
699 }
700
701
702 /* Join all the threads */
703 for(index=0; index<(arg*4); index++) {
704 PR_JoinThread(list[index].thread);
705 if (list[index].internal) {
706 PR_Lock(list[index].lock);
707 PR_DestroyCondVar(list[index].cvar);
708 PR_Unlock(list[index].lock);
709 PR_DestroyLock(list[index].lock);
710 }
711 }
712
713 PR_DestroyCondVar(sharedcvar);
714 PR_DestroyLock(sharedlock);
715 PR_DestroyCondVar(exitcvar);
716 PR_DestroyLock(exitlock);
717
718 PR_DELETE(list);
719 }
720
721 void
CondVarMixedTest(void * _arg)722 CondVarMixedTest(void *_arg)
723 {
724 PRInt32 arg = (PRInt32)_arg;
725 PRInt32 index, loops;
726 threadinfo *list;
727 PRLock *sharedlock;
728 PRCondVar *sharedcvar;
729 PRLock *exitlock;
730 PRCondVar *exitcvar;
731 PRInt32 *ptcount;
732
733 exitcount=0;
734 tcount=0;
735 list = (threadinfo *)PR_MALLOC(sizeof(threadinfo) * (arg * 4));
736 ptcount = (PRInt32 *)PR_CALLOC(sizeof(*ptcount) * (arg * 4));
737
738 sharedlock = PR_NewLock();
739 sharedcvar = PR_NewCondVar(sharedlock);
740 exitlock = PR_NewLock();
741 exitcvar = PR_NewCondVar(exitlock);
742
743 /* Create the threads */
744 for(index=0; index<arg*4; ) {
745 CreateTestThread(&list[index],
746 index,
747 sharedlock,
748 sharedcvar,
749 count,
750 PR_MillisecondsToInterval(50),
751 &tcount,
752 exitlock,
753 exitcvar,
754 &exitcount,
755 PR_TRUE,
756 PR_LOCAL_THREAD);
757 index++;
758 CreateTestThread(&list[index],
759 index,
760 sharedlock,
761 sharedcvar,
762 count,
763 PR_MillisecondsToInterval(50),
764 &tcount,
765 exitlock,
766 exitcvar,
767 &exitcount,
768 PR_TRUE,
769 PR_GLOBAL_THREAD);
770 index++;
771 list[index].lock = PR_NewLock();
772 list[index].cvar = PR_NewCondVar(list[index].lock);
773 CreateTestThread(&list[index],
774 index,
775 list[index].lock,
776 list[index].cvar,
777 count,
778 PR_MillisecondsToInterval(50),
779 ptcount,
780 exitlock,
781 exitcvar,
782 &exitcount,
783 PR_FALSE,
784 PR_LOCAL_THREAD);
785 index++;
786 ptcount++;
787
788 list[index].lock = PR_NewLock();
789 list[index].cvar = PR_NewCondVar(list[index].lock);
790 CreateTestThread(&list[index],
791 index,
792 list[index].lock,
793 list[index].cvar,
794 count,
795 PR_MillisecondsToInterval(50),
796 ptcount,
797 exitlock,
798 exitcvar,
799 &exitcount,
800 PR_FALSE,
801 PR_GLOBAL_THREAD);
802 index++;
803 ptcount++;
804 }
805
806
807 /* Notify every 3rd thread */
808 for (loops = 0; loops < count; loops++) {
809
810 /* Notify the threads */
811 for(index=0; index<(arg*4); index+=3) {
812
813 PR_Lock(list[index].lock);
814 *list[index].tcount++;
815 PR_NotifyCondVar(list[index].cvar);
816 PR_Unlock(list[index].lock);
817
818 }
819 /* Wait for threads to finish */
820 PR_Lock(exitlock);
821 while(exitcount < arg*4) {
822 PR_WaitCondVar(exitcvar, PR_SecondsToInterval(60));
823 }
824 PR_ASSERT(exitcount >= arg*4);
825 exitcount -= arg*4;
826 PR_Unlock(exitlock);
827 }
828
829 /* Join all the threads */
830 for(index=0; index<(arg*4); index++) {
831 PR_JoinThread(list[index].thread);
832 if (list[index].internal) {
833 PR_Lock(list[index].lock);
834 PR_DestroyCondVar(list[index].cvar);
835 PR_Unlock(list[index].lock);
836 PR_DestroyLock(list[index].lock);
837 }
838 }
839
840 PR_DestroyCondVar(sharedcvar);
841 PR_DestroyLock(sharedlock);
842
843 PR_DELETE(list);
844 }
845
846 void
CondVarCombinedTest(void * arg)847 CondVarCombinedTest(void *arg)
848 {
849 PRThread *threads[3];
850
851 threads[0] = PR_CreateThread(PR_USER_THREAD,
852 CondVarTest,
853 (void *)arg,
854 PR_PRIORITY_NORMAL,
855 PR_GLOBAL_THREAD,
856 PR_JOINABLE_THREAD,
857 0);
858 threads[1] = PR_CreateThread(PR_USER_THREAD,
859 CondVarTimeoutTest,
860 (void *)arg,
861 PR_PRIORITY_NORMAL,
862 PR_GLOBAL_THREAD,
863 PR_JOINABLE_THREAD,
864 0);
865 threads[2] = PR_CreateThread(PR_USER_THREAD,
866 CondVarMixedTest,
867 (void *)arg,
868 PR_PRIORITY_NORMAL,
869 PR_GLOBAL_THREAD,
870 PR_JOINABLE_THREAD,
871 0);
872
873 PR_JoinThread(threads[0]);
874 PR_JoinThread(threads[1]);
875 PR_JoinThread(threads[2]);
876 }
877
878 /************************************************************************/
879
Measure(void (* func)(void *),PRInt32 arg,const char * msg)880 static void Measure(void (*func)(void *), PRInt32 arg, const char *msg)
881 {
882 PRIntervalTime start, stop;
883 double d;
884
885 start = PR_IntervalNow();
886 (*func)((void *)arg);
887 stop = PR_IntervalNow();
888
889 d = (double)PR_IntervalToMicroseconds(stop - start);
890
891 printf("%40s: %6.2f usec\n", msg, d / count);
892 }
893
RealMain(int argc,char ** argv)894 static PRIntn PR_CALLBACK RealMain(int argc, char **argv)
895 {
896 PRInt32 threads, default_threads = DEFAULT_THREADS;
897 PLOptStatus os;
898 PLOptState *opt = PL_CreateOptState(argc, argv, "vc:t:");
899 while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
900 {
901 if (PL_OPT_BAD == os) {
902 continue;
903 }
904 switch (opt->option)
905 {
906 case 'v': /* debug mode */
907 _debug_on = 1;
908 break;
909 case 'c': /* loop counter */
910 count = atoi(opt->value);
911 break;
912 case 't': /* number of threads involved */
913 default_threads = atoi(opt->value);
914 break;
915 default:
916 break;
917 }
918 }
919 PL_DestroyOptState(opt);
920
921 if (0 == count) {
922 count = DEFAULT_COUNT;
923 }
924 if (0 == default_threads) {
925 default_threads = DEFAULT_THREADS;
926 }
927
928 printf("\n\
929 CondVar Test: \n\
930 \n\
931 Simple test creates several local and global threads; half use a single,\n\
932 shared condvar, and the other half have their own condvar. The main \n\
933 thread then loops notifying them to wakeup. \n\
934 \n\
935 The timeout test is very similar except that the threads are not \n\
936 notified. They will all wakeup on a 1 second timeout. \n\
937 \n\
938 The mixed test combines the simple test and the timeout test; every \n\
939 third thread is notified, the other threads are expected to timeout \n\
940 correctly. \n\
941 \n\
942 Lastly, the combined test creates a thread for each of the above three \n\
943 cases and they all run simultaneously. \n\
944 \n\
945 This test is run with %d, %d, %d, and %d threads of each type.\n\n",
946 default_threads, default_threads*2, default_threads*3, default_threads*4);
947
948 PR_SetConcurrency(2);
949
950 for (threads = default_threads; threads < default_threads*5; threads+=default_threads) {
951 printf("\n%ld Thread tests\n", threads);
952 Measure(CondVarTestSUU, threads, "Condvar simple test shared UU");
953 Measure(CondVarTestSUK, threads, "Condvar simple test shared UK");
954 Measure(CondVarTestPUU, threads, "Condvar simple test priv UU");
955 Measure(CondVarTestPUK, threads, "Condvar simple test priv UK");
956 Measure(CondVarTest, threads, "Condvar simple test All");
957 Measure(CondVarTimeoutTest, threads, "Condvar timeout test");
958 #if 0
959 Measure(CondVarMixedTest, threads, "Condvar mixed timeout test");
960 Measure(CondVarCombinedTest, threads, "Combined condvar test");
961 #endif
962 }
963
964 printf("PASS\n");
965
966 return 0;
967 }
968
main(int argc,char ** argv)969 int main(int argc, char **argv)
970 {
971 PRIntn rv;
972
973 PR_STDIO_INIT();
974 rv = PR_Initialize(RealMain, argc, argv, 0);
975 return rv;
976 } /* main */
977