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