1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
3
* The contents of this file are subject to the Mozilla Public
4
* License Version 1.1 (the "License"); you may not use this file
5
* except in compliance with the License. You may obtain a copy of
6
* the License at http://www.mozilla.org/MPL/
8
* Software distributed under the License is distributed on an "AS
9
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
10
* implied. See the License for the specific language governing
11
* rights and limitations under the License.
13
* The Original Code is the Netscape Portable Runtime (NSPR).
15
* The Initial Developer of the Original Code is Netscape
16
* Communications Corporation. Portions created by Netscape are
17
* Copyright (C) 1998-2000 Netscape Communications Corporation. All
22
* Alternatively, the contents of this file may be used under the
23
* terms of the GNU General Public License Version 2 or later (the
24
* "GPL"), in which case the provisions of the GPL are applicable
25
* instead of those above. If you wish to allow use of your
26
* version of this file only under the terms of the GPL and not to
27
* allow others to use your version of this file under the MPL,
28
* indicate your decision by deleting the provisions above and
29
* replace them with the notice and other provisions required by
30
* the GPL. If you do not delete the provisions above, a recipient
31
* may use your version of this file under either the MPL or the
35
/***********************************************************************
36
** 1996 - Netscape Communications Corporation
40
** Description: Simple test creates several local and global threads;
41
** half use a single,shared condvar, and the
42
** other half have their own condvar. The main thread then loops
43
** notifying them to wakeup.
45
** Modification History:
46
** 14-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
47
** The debug mode will print all of the printfs associated with this test.
48
** The regress mode will be the default mode. Since the regress tool limits
49
** the output to a one line status:PASS or FAIL,all of the printf statements
50
** have been handled with an if (debug_mode) statement.
51
***********************************************************************/
62
#define DPRINTF(arg) if (_debug_on) printf arg
66
#define printf PR_LogPrint
67
extern void SetupMacPrintfLog(char *logFile);
70
#define DEFAULT_COUNT 100
71
#define DEFAULT_THREADS 5
72
PRInt32 count = DEFAULT_COUNT;
74
typedef struct threadinfo {
81
PRIntervalTime timeout;
90
** Make exitcount, tcount static. for Win16.
92
static PRInt32 exitcount=0;
93
static PRInt32 tcount=0;
96
/* Thread that gets notified; many threads share the same condvar */
98
SharedCondVarThread(void *_info)
100
threadinfo *info = (threadinfo *)_info;
103
for (index=0; index<info->loops; index++) {
105
if (*info->tcount == 0)
106
PR_WaitCondVar(info->cvar, info->timeout);
108
printf("shared thread %ld notified in loop %ld\n", info->id, index);
111
PR_Unlock(info->lock);
113
PR_Lock(info->exitlock);
114
(*info->exitcount)++;
115
PR_NotifyCondVar(info->exitcvar);
116
PR_Unlock(info->exitlock);
119
printf("shared thread %ld terminating\n", info->id);
123
/* Thread that gets notified; no other threads use the same condvar */
125
PrivateCondVarThread(void *_info)
127
threadinfo *info = (threadinfo *)_info;
130
for (index=0; index<info->loops; index++) {
132
if (*info->tcount == 0) {
133
DPRINTF(("PrivateCondVarThread: thread 0x%lx waiting on cvar = 0x%lx\n",
134
PR_GetCurrentThread(), info->cvar));
135
PR_WaitCondVar(info->cvar, info->timeout);
138
printf("solo thread %ld notified in loop %ld\n", info->id, index);
141
PR_Unlock(info->lock);
143
PR_Lock(info->exitlock);
144
(*info->exitcount)++;
145
PR_NotifyCondVar(info->exitcvar);
146
DPRINTF(("PrivateCondVarThread: thread 0x%lx notified exitcvar = 0x%lx cnt = %ld\n",
147
PR_GetCurrentThread(), info->exitcvar,(*info->exitcount)));
148
PR_Unlock(info->exitlock);
151
printf("solo thread %ld terminating\n", info->id);
156
CreateTestThread(threadinfo *info,
161
PRIntervalTime timeout,
170
info->internal = (shared) ? PR_FALSE : PR_TRUE;
174
info->timeout = timeout;
175
info->tcount = tcount;
176
info->exitlock = exitlock;
177
info->exitcvar = exitcvar;
178
info->exitcount = exitcount;
179
info->thread = PR_CreateThread(
181
shared?SharedCondVarThread:PrivateCondVarThread,
188
PL_PrintError("error creating thread\n");
193
CondVarTestSUU(void *_arg)
195
PRInt32 arg = (PRInt32)_arg;
196
PRInt32 index, loops;
199
PRCondVar *sharedcvar;
205
list = (threadinfo *)PR_MALLOC(sizeof(threadinfo) * (arg * 4));
207
sharedlock = PR_NewLock();
208
sharedcvar = PR_NewCondVar(sharedlock);
209
exitlock = PR_NewLock();
210
exitcvar = PR_NewCondVar(exitlock);
212
/* Create the threads */
213
for(index=0; index<arg; ) {
214
CreateTestThread(&list[index],
219
PR_INTERVAL_NO_TIMEOUT,
227
DPRINTF(("CondVarTestSUU: created thread 0x%lx\n",list[index].thread));
230
for (loops = 0; loops < count; loops++) {
231
/* Notify the threads */
232
for(index=0; index<(arg); index++) {
233
PR_Lock(list[index].lock);
234
(*list[index].tcount)++;
235
PR_NotifyCondVar(list[index].cvar);
236
PR_Unlock(list[index].lock);
237
DPRINTF(("PrivateCondVarThread: thread 0x%lx notified cvar = 0x%lx\n",
238
PR_GetCurrentThread(), list[index].cvar));
241
/* Wait for threads to finish */
243
while(exitcount < arg)
244
PR_WaitCondVar(exitcvar, PR_SecondsToInterval(60));
245
PR_ASSERT(exitcount >= arg);
250
/* Join all the threads */
251
for(index=0; index<(arg); index++)
252
PR_JoinThread(list[index].thread);
254
PR_DestroyCondVar(sharedcvar);
255
PR_DestroyLock(sharedlock);
256
PR_DestroyCondVar(exitcvar);
257
PR_DestroyLock(exitlock);
263
CondVarTestSUK(void *_arg)
265
PRInt32 arg = (PRInt32)_arg;
266
PRInt32 index, loops;
269
PRCondVar *sharedcvar;
275
list = (threadinfo *)PR_MALLOC(sizeof(threadinfo) * (arg * 4));
277
sharedlock = PR_NewLock();
278
sharedcvar = PR_NewCondVar(sharedlock);
279
exitlock = PR_NewLock();
280
exitcvar = PR_NewCondVar(exitlock);
282
/* Create the threads */
283
for(index=0; index<arg; ) {
284
CreateTestThread(&list[index],
289
PR_INTERVAL_NO_TIMEOUT,
299
for (loops = 0; loops < count; loops++) {
300
/* Notify the threads */
301
for(index=0; index<(arg); index++) {
303
PR_Lock(list[index].lock);
304
(*list[index].tcount)++;
305
PR_NotifyCondVar(list[index].cvar);
306
PR_Unlock(list[index].lock);
310
printf("wait for threads to be done\n");
312
/* Wait for threads to finish */
314
while(exitcount < arg)
315
PR_WaitCondVar(exitcvar, PR_SecondsToInterval(60));
316
PR_ASSERT(exitcount >= arg);
320
printf("threads ready\n");
324
/* Join all the threads */
325
for(index=0; index<(arg); index++)
326
PR_JoinThread(list[index].thread);
328
PR_DestroyCondVar(sharedcvar);
329
PR_DestroyLock(sharedlock);
330
PR_DestroyCondVar(exitcvar);
331
PR_DestroyLock(exitlock);
337
CondVarTestPUU(void *_arg)
339
PRInt32 arg = (PRInt32)_arg;
340
PRInt32 index, loops;
343
PRCondVar *sharedcvar;
346
PRInt32 *tcount, *saved_tcount;
349
list = (threadinfo *)PR_MALLOC(sizeof(threadinfo) * (arg * 4));
350
saved_tcount = tcount = (PRInt32 *)PR_CALLOC(sizeof(*tcount) * (arg * 4));
352
sharedlock = PR_NewLock();
353
sharedcvar = PR_NewCondVar(sharedlock);
354
exitlock = PR_NewLock();
355
exitcvar = PR_NewCondVar(exitlock);
357
/* Create the threads */
358
for(index=0; index<arg; ) {
359
list[index].lock = PR_NewLock();
360
list[index].cvar = PR_NewCondVar(list[index].lock);
361
CreateTestThread(&list[index],
366
PR_INTERVAL_NO_TIMEOUT,
374
DPRINTF(("CondVarTestPUU: created thread 0x%lx\n",list[index].thread));
379
for (loops = 0; loops < count; loops++) {
380
/* Notify the threads */
381
for(index=0; index<(arg); index++) {
383
PR_Lock(list[index].lock);
384
(*list[index].tcount)++;
385
PR_NotifyCondVar(list[index].cvar);
386
PR_Unlock(list[index].lock);
390
/* Wait for threads to finish */
391
while(exitcount < arg) {
392
DPRINTF(("CondVarTestPUU: thread 0x%lx waiting on exitcvar = 0x%lx cnt = %ld\n",
393
PR_GetCurrentThread(), exitcvar, exitcount));
394
PR_WaitCondVar(exitcvar, PR_SecondsToInterval(60));
396
PR_ASSERT(exitcount >= arg);
401
/* Join all the threads */
402
for(index=0; index<(arg); index++) {
403
DPRINTF(("CondVarTestPUU: joining thread 0x%lx\n",list[index].thread));
404
PR_JoinThread(list[index].thread);
405
if (list[index].internal) {
406
PR_Lock(list[index].lock);
407
PR_DestroyCondVar(list[index].cvar);
408
PR_Unlock(list[index].lock);
409
PR_DestroyLock(list[index].lock);
413
PR_DestroyCondVar(sharedcvar);
414
PR_DestroyLock(sharedlock);
415
PR_DestroyCondVar(exitcvar);
416
PR_DestroyLock(exitlock);
419
PR_DELETE(saved_tcount);
423
CondVarTestPUK(void *_arg)
425
PRInt32 arg = (PRInt32)_arg;
426
PRInt32 index, loops;
429
PRCondVar *sharedcvar;
432
PRInt32 *tcount, *saved_tcount;
435
list = (threadinfo *)PR_MALLOC(sizeof(threadinfo) * (arg * 4));
436
saved_tcount = tcount = (PRInt32 *)PR_CALLOC(sizeof(*tcount) * (arg * 4));
438
sharedlock = PR_NewLock();
439
sharedcvar = PR_NewCondVar(sharedlock);
440
exitlock = PR_NewLock();
441
exitcvar = PR_NewCondVar(exitlock);
443
/* Create the threads */
444
for(index=0; index<arg; ) {
445
list[index].lock = PR_NewLock();
446
list[index].cvar = PR_NewCondVar(list[index].lock);
447
CreateTestThread(&list[index],
452
PR_INTERVAL_NO_TIMEOUT,
464
for (loops = 0; loops < count; loops++) {
465
/* Notify the threads */
466
for(index=0; index<(arg); index++) {
468
PR_Lock(list[index].lock);
469
(*list[index].tcount)++;
470
PR_NotifyCondVar(list[index].cvar);
471
PR_Unlock(list[index].lock);
474
/* Wait for threads to finish */
476
while(exitcount < arg)
477
PR_WaitCondVar(exitcvar, PR_SecondsToInterval(60));
478
PR_ASSERT(exitcount >= arg);
483
/* Join all the threads */
484
for(index=0; index<(arg); index++) {
485
PR_JoinThread(list[index].thread);
486
if (list[index].internal) {
487
PR_Lock(list[index].lock);
488
PR_DestroyCondVar(list[index].cvar);
489
PR_Unlock(list[index].lock);
490
PR_DestroyLock(list[index].lock);
494
PR_DestroyCondVar(sharedcvar);
495
PR_DestroyLock(sharedlock);
496
PR_DestroyCondVar(exitcvar);
497
PR_DestroyLock(exitlock);
500
PR_DELETE(saved_tcount);
504
CondVarTest(void *_arg)
506
PRInt32 arg = (PRInt32)_arg;
507
PRInt32 index, loops;
510
PRCondVar *sharedcvar;
513
PRInt32 *ptcount, *saved_ptcount;
517
list = (threadinfo *)PR_MALLOC(sizeof(threadinfo) * (arg * 4));
518
saved_ptcount = ptcount = (PRInt32 *)PR_CALLOC(sizeof(*ptcount) * (arg * 4));
520
sharedlock = PR_NewLock();
521
sharedcvar = PR_NewCondVar(sharedlock);
522
exitlock = PR_NewLock();
523
exitcvar = PR_NewCondVar(exitlock);
525
/* Create the threads */
526
for(index=0; index<arg*4; ) {
527
CreateTestThread(&list[index],
532
PR_INTERVAL_NO_TIMEOUT,
541
CreateTestThread(&list[index],
546
PR_INTERVAL_NO_TIMEOUT,
555
list[index].lock = PR_NewLock();
556
list[index].cvar = PR_NewCondVar(list[index].lock);
557
CreateTestThread(&list[index],
562
PR_INTERVAL_NO_TIMEOUT,
571
list[index].lock = PR_NewLock();
572
list[index].cvar = PR_NewCondVar(list[index].lock);
573
CreateTestThread(&list[index],
578
PR_INTERVAL_NO_TIMEOUT,
590
for (loops = 0; loops < count; loops++) {
592
/* Notify the threads */
593
for(index=0; index<(arg*4); index++) {
594
PR_Lock(list[index].lock);
595
(*list[index].tcount)++;
596
PR_NotifyCondVar(list[index].cvar);
597
PR_Unlock(list[index].lock);
601
printf("wait for threads done\n");
604
/* Wait for threads to finish */
606
while(exitcount < arg*4)
607
PR_WaitCondVar(exitcvar, PR_SecondsToInterval(60));
608
PR_ASSERT(exitcount >= arg*4);
612
printf("threads ready\n");
616
/* Join all the threads */
617
for(index=0; index<(arg*4); index++) {
618
PR_JoinThread(list[index].thread);
619
if (list[index].internal) {
620
PR_Lock(list[index].lock);
621
PR_DestroyCondVar(list[index].cvar);
622
PR_Unlock(list[index].lock);
623
PR_DestroyLock(list[index].lock);
627
PR_DestroyCondVar(sharedcvar);
628
PR_DestroyLock(sharedlock);
629
PR_DestroyCondVar(exitcvar);
630
PR_DestroyLock(exitlock);
633
PR_DELETE(saved_ptcount);
637
CondVarTimeoutTest(void *_arg)
639
PRInt32 arg = (PRInt32)_arg;
640
PRInt32 index, loops;
643
PRCondVar *sharedcvar;
647
list = (threadinfo *)PR_MALLOC(sizeof(threadinfo) * (arg * 4));
649
sharedlock = PR_NewLock();
650
sharedcvar = PR_NewCondVar(sharedlock);
651
exitlock = PR_NewLock();
652
exitcvar = PR_NewCondVar(exitlock);
654
/* Create the threads */
655
for(index=0; index<arg*4; ) {
656
CreateTestThread(&list[index],
661
PR_MillisecondsToInterval(50),
669
CreateTestThread(&list[index],
674
PR_MillisecondsToInterval(50),
682
list[index].lock = PR_NewLock();
683
list[index].cvar = PR_NewCondVar(list[index].lock);
684
CreateTestThread(&list[index],
689
PR_MillisecondsToInterval(50),
698
list[index].lock = PR_NewLock();
699
list[index].cvar = PR_NewCondVar(list[index].lock);
700
CreateTestThread(&list[index],
705
PR_MillisecondsToInterval(50),
716
for (loops = 0; loops < count; loops++) {
718
/* Wait for threads to finish */
720
while(exitcount < arg*4)
721
PR_WaitCondVar(exitcvar, PR_SecondsToInterval(60));
722
PR_ASSERT(exitcount >= arg*4);
728
/* Join all the threads */
729
for(index=0; index<(arg*4); index++) {
730
PR_JoinThread(list[index].thread);
731
if (list[index].internal) {
732
PR_Lock(list[index].lock);
733
PR_DestroyCondVar(list[index].cvar);
734
PR_Unlock(list[index].lock);
735
PR_DestroyLock(list[index].lock);
739
PR_DestroyCondVar(sharedcvar);
740
PR_DestroyLock(sharedlock);
741
PR_DestroyCondVar(exitcvar);
742
PR_DestroyLock(exitlock);
748
CondVarMixedTest(void *_arg)
750
PRInt32 arg = (PRInt32)_arg;
751
PRInt32 index, loops;
754
PRCondVar *sharedcvar;
761
list = (threadinfo *)PR_MALLOC(sizeof(threadinfo) * (arg * 4));
762
ptcount = (PRInt32 *)PR_CALLOC(sizeof(*ptcount) * (arg * 4));
764
sharedlock = PR_NewLock();
765
sharedcvar = PR_NewCondVar(sharedlock);
766
exitlock = PR_NewLock();
767
exitcvar = PR_NewCondVar(exitlock);
769
/* Create the threads */
770
for(index=0; index<arg*4; ) {
771
CreateTestThread(&list[index],
776
PR_MillisecondsToInterval(50),
784
CreateTestThread(&list[index],
789
PR_MillisecondsToInterval(50),
797
list[index].lock = PR_NewLock();
798
list[index].cvar = PR_NewCondVar(list[index].lock);
799
CreateTestThread(&list[index],
804
PR_MillisecondsToInterval(50),
814
list[index].lock = PR_NewLock();
815
list[index].cvar = PR_NewCondVar(list[index].lock);
816
CreateTestThread(&list[index],
821
PR_MillisecondsToInterval(50),
833
/* Notify every 3rd thread */
834
for (loops = 0; loops < count; loops++) {
836
/* Notify the threads */
837
for(index=0; index<(arg*4); index+=3) {
839
PR_Lock(list[index].lock);
840
*list[index].tcount++;
841
PR_NotifyCondVar(list[index].cvar);
842
PR_Unlock(list[index].lock);
845
/* Wait for threads to finish */
847
while(exitcount < arg*4)
848
PR_WaitCondVar(exitcvar, PR_SecondsToInterval(60));
849
PR_ASSERT(exitcount >= arg*4);
854
/* Join all the threads */
855
for(index=0; index<(arg*4); index++) {
856
PR_JoinThread(list[index].thread);
857
if (list[index].internal) {
858
PR_Lock(list[index].lock);
859
PR_DestroyCondVar(list[index].cvar);
860
PR_Unlock(list[index].lock);
861
PR_DestroyLock(list[index].lock);
865
PR_DestroyCondVar(sharedcvar);
866
PR_DestroyLock(sharedlock);
872
CondVarCombinedTest(void *arg)
874
PRThread *threads[3];
876
threads[0] = PR_CreateThread(PR_USER_THREAD,
883
threads[1] = PR_CreateThread(PR_USER_THREAD,
890
threads[2] = PR_CreateThread(PR_USER_THREAD,
898
PR_JoinThread(threads[0]);
899
PR_JoinThread(threads[1]);
900
PR_JoinThread(threads[2]);
903
/************************************************************************/
905
static void Measure(void (*func)(void *), PRInt32 arg, const char *msg)
907
PRIntervalTime start, stop;
910
start = PR_IntervalNow();
911
(*func)((void *)arg);
912
stop = PR_IntervalNow();
914
d = (double)PR_IntervalToMicroseconds(stop - start);
916
printf("%40s: %6.2f usec\n", msg, d / count);
919
static PRIntn PR_CALLBACK RealMain(int argc, char **argv)
921
PRInt32 threads, default_threads = DEFAULT_THREADS;
923
PLOptState *opt = PL_CreateOptState(argc, argv, "vc:t:");
924
while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
926
if (PL_OPT_BAD == os) continue;
929
case 'v': /* debug mode */
932
case 'c': /* loop counter */
933
count = atoi(opt->value);
935
case 't': /* number of threads involved */
936
default_threads = atoi(opt->value);
942
PL_DestroyOptState(opt);
944
if (0 == count) count = DEFAULT_COUNT;
945
if (0 == default_threads) default_threads = DEFAULT_THREADS;
948
SetupMacPrintfLog("cvar2.log");
954
Simple test creates several local and global threads; half use a single,\n\
955
shared condvar, and the other half have their own condvar. The main \n\
956
thread then loops notifying them to wakeup. \n\
958
The timeout test is very similar except that the threads are not \n\
959
notified. They will all wakeup on a 1 second timeout. \n\
961
The mixed test combines the simple test and the timeout test; every \n\
962
third thread is notified, the other threads are expected to timeout \n\
965
Lastly, the combined test creates a thread for each of the above three \n\
966
cases and they all run simultaneously. \n\
968
This test is run with %d, %d, %d, and %d threads of each type.\n\n",
969
default_threads, default_threads*2, default_threads*3, default_threads*4);
971
PR_SetConcurrency(2);
973
for (threads = default_threads; threads < default_threads*5; threads+=default_threads) {
974
printf("\n%ld Thread tests\n", threads);
975
Measure(CondVarTestSUU, threads, "Condvar simple test shared UU");
976
Measure(CondVarTestSUK, threads, "Condvar simple test shared UK");
977
Measure(CondVarTestPUU, threads, "Condvar simple test priv UU");
978
Measure(CondVarTestPUK, threads, "Condvar simple test priv UK");
980
/* Mac heaps can't handle thread*4 stack allocations at a time for (10, 15, 20)*4 */
981
Measure(CondVarTest, 5, "Condvar simple test All");
982
Measure(CondVarTimeoutTest, 5, "Condvar timeout test");
984
Measure(CondVarTest, threads, "Condvar simple test All");
985
Measure(CondVarTimeoutTest, threads, "Condvar timeout test");
988
Measure(CondVarMixedTest, threads, "Condvar mixed timeout test");
989
Measure(CondVarCombinedTest, threads, "Combined condvar test");
998
PRIntn main(PRIntn argc, char *argv[])
1003
rv = PR_Initialize(RealMain, argc, argv, 0);