tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

cvar2.c (23898B)


      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
     19 *test.
     20 **           The regress mode will be the default mode. Since the regress tool
     21 *limits
     22 **           the output to a one line status:PASS or FAIL,all of the printf
     23 *statements
     24 **           have been handled with an if (debug_mode) statement.
     25 ***********************************************************************/
     26 
     27 #include "nspr.h"
     28 #include "plerror.h"
     29 #include "plgetopt.h"
     30 
     31 #include <stdio.h>
     32 #include <stdlib.h>
     33 #include <string.h>
     34 
     35 int _debug_on = 0;
     36 #define DPRINTF(arg) \
     37  if (_debug_on) printf arg
     38 
     39 #define DEFAULT_COUNT 100
     40 #define DEFAULT_THREADS 5
     41 PRInt32 count = DEFAULT_COUNT;
     42 
     43 typedef struct threadinfo {
     44  PRThread* thread;
     45  PRInt32 id;
     46  PRBool internal;
     47  PRInt32* tcount;
     48  PRLock* lock;
     49  PRCondVar* cvar;
     50  PRIntervalTime timeout;
     51  PRInt32 loops;
     52 
     53  PRLock* exitlock;
     54  PRCondVar* exitcvar;
     55  PRInt32* exitcount;
     56 } threadinfo;
     57 
     58 /*
     59 ** Make exitcount, tcount static. for Win16.
     60 */
     61 static PRInt32 exitcount = 0;
     62 static PRInt32 tcount = 0;
     63 
     64 /* Thread that gets notified; many threads share the same condvar */
     65 void PR_CALLBACK SharedCondVarThread(void* _info) {
     66  threadinfo* info = (threadinfo*)_info;
     67  PRInt32 index;
     68 
     69  for (index = 0; index < info->loops; index++) {
     70    PR_Lock(info->lock);
     71    if (*info->tcount == 0) {
     72      PR_WaitCondVar(info->cvar, info->timeout);
     73    }
     74 #if 0
     75        printf("shared thread %ld notified in loop %ld\n", info->id, index);
     76 #endif
     77    (*info->tcount)--;
     78    PR_Unlock(info->lock);
     79 
     80    PR_Lock(info->exitlock);
     81    (*info->exitcount)++;
     82    PR_NotifyCondVar(info->exitcvar);
     83    PR_Unlock(info->exitlock);
     84  }
     85 #if 0
     86    printf("shared thread %ld terminating\n", info->id);
     87 #endif
     88 }
     89 
     90 /* Thread that gets notified; no other threads use the same condvar */
     91 void PR_CALLBACK PrivateCondVarThread(void* _info) {
     92  threadinfo* info = (threadinfo*)_info;
     93  PRInt32 index;
     94 
     95  for (index = 0; index < info->loops; index++) {
     96    PR_Lock(info->lock);
     97    if (*info->tcount == 0) {
     98      DPRINTF(("PrivateCondVarThread: thread 0x%lx waiting on cvar = 0x%lx\n",
     99               PR_GetCurrentThread(), info->cvar));
    100      PR_WaitCondVar(info->cvar, info->timeout);
    101    }
    102 #if 0
    103        printf("solo   thread %ld notified in loop %ld\n", info->id, index);
    104 #endif
    105    (*info->tcount)--;
    106    PR_Unlock(info->lock);
    107 
    108    PR_Lock(info->exitlock);
    109    (*info->exitcount)++;
    110    PR_NotifyCondVar(info->exitcvar);
    111    DPRINTF(
    112        ("PrivateCondVarThread: thread 0x%lx notified exitcvar = 0x%lx cnt = "
    113         "%ld\n",
    114         PR_GetCurrentThread(), info->exitcvar, (*info->exitcount)));
    115    PR_Unlock(info->exitlock);
    116  }
    117 #if 0
    118    printf("solo   thread %ld terminating\n", info->id);
    119 #endif
    120 }
    121 
    122 void CreateTestThread(threadinfo* info, PRInt32 id, PRLock* lock,
    123                      PRCondVar* cvar, PRInt32 loops, PRIntervalTime timeout,
    124                      PRInt32* tcount, PRLock* exitlock, PRCondVar* exitcvar,
    125                      PRInt32* exitcount, PRBool shared, PRThreadScope scope) {
    126  info->id = id;
    127  info->internal = (shared) ? PR_FALSE : PR_TRUE;
    128  info->lock = lock;
    129  info->cvar = cvar;
    130  info->loops = loops;
    131  info->timeout = timeout;
    132  info->tcount = tcount;
    133  info->exitlock = exitlock;
    134  info->exitcvar = exitcvar;
    135  info->exitcount = exitcount;
    136  info->thread = PR_CreateThread(
    137      PR_USER_THREAD, shared ? SharedCondVarThread : PrivateCondVarThread, info,
    138      PR_PRIORITY_NORMAL, scope, PR_JOINABLE_THREAD, 0);
    139  if (!info->thread) {
    140    PL_PrintError("error creating thread\n");
    141  }
    142 }
    143 
    144 void CondVarTestSUU(void* _arg) {
    145  PRInt32 arg = (PRInt32)_arg;
    146  PRInt32 index, loops;
    147  threadinfo* list;
    148  PRLock* sharedlock;
    149  PRCondVar* sharedcvar;
    150  PRLock* exitlock;
    151  PRCondVar* exitcvar;
    152 
    153  exitcount = 0;
    154  tcount = 0;
    155  list = (threadinfo*)PR_MALLOC(sizeof(threadinfo) * (arg * 4));
    156 
    157  sharedlock = PR_NewLock();
    158  sharedcvar = PR_NewCondVar(sharedlock);
    159  exitlock = PR_NewLock();
    160  exitcvar = PR_NewCondVar(exitlock);
    161 
    162  /* Create the threads */
    163  for (index = 0; index < arg;) {
    164    CreateTestThread(&list[index], index, sharedlock, sharedcvar, count,
    165                     PR_INTERVAL_NO_TIMEOUT, &tcount, exitlock, exitcvar,
    166                     &exitcount, PR_TRUE, PR_LOCAL_THREAD);
    167    index++;
    168    DPRINTF(("CondVarTestSUU: created thread 0x%lx\n", list[index].thread));
    169  }
    170 
    171  for (loops = 0; loops < count; loops++) {
    172    /* Notify the threads */
    173    for (index = 0; index < (arg); index++) {
    174      PR_Lock(list[index].lock);
    175      (*list[index].tcount)++;
    176      PR_NotifyCondVar(list[index].cvar);
    177      PR_Unlock(list[index].lock);
    178      DPRINTF(("PrivateCondVarThread: thread 0x%lx notified cvar = 0x%lx\n",
    179               PR_GetCurrentThread(), list[index].cvar));
    180    }
    181 
    182    /* Wait for threads to finish */
    183    PR_Lock(exitlock);
    184    while (exitcount < arg) {
    185      PR_WaitCondVar(exitcvar, PR_SecondsToInterval(60));
    186    }
    187    PR_ASSERT(exitcount >= arg);
    188    exitcount -= arg;
    189    PR_Unlock(exitlock);
    190  }
    191 
    192  /* Join all the threads */
    193  for (index = 0; index < (arg); index++) {
    194    PR_JoinThread(list[index].thread);
    195  }
    196 
    197  PR_DestroyCondVar(sharedcvar);
    198  PR_DestroyLock(sharedlock);
    199  PR_DestroyCondVar(exitcvar);
    200  PR_DestroyLock(exitlock);
    201 
    202  PR_DELETE(list);
    203 }
    204 
    205 void CondVarTestSUK(void* _arg) {
    206  PRInt32 arg = (PRInt32)_arg;
    207  PRInt32 index, loops;
    208  threadinfo* list;
    209  PRLock* sharedlock;
    210  PRCondVar* sharedcvar;
    211  PRLock* exitlock;
    212  PRCondVar* exitcvar;
    213  exitcount = 0;
    214  tcount = 0;
    215 
    216  list = (threadinfo*)PR_MALLOC(sizeof(threadinfo) * (arg * 4));
    217 
    218  sharedlock = PR_NewLock();
    219  sharedcvar = PR_NewCondVar(sharedlock);
    220  exitlock = PR_NewLock();
    221  exitcvar = PR_NewCondVar(exitlock);
    222 
    223  /* Create the threads */
    224  for (index = 0; index < arg;) {
    225    CreateTestThread(&list[index], index, sharedlock, sharedcvar, count,
    226                     PR_INTERVAL_NO_TIMEOUT, &tcount, exitlock, exitcvar,
    227                     &exitcount, PR_TRUE, PR_GLOBAL_THREAD);
    228    index++;
    229  }
    230 
    231  for (loops = 0; loops < count; loops++) {
    232    /* Notify the threads */
    233    for (index = 0; index < (arg); index++) {
    234      PR_Lock(list[index].lock);
    235      (*list[index].tcount)++;
    236      PR_NotifyCondVar(list[index].cvar);
    237      PR_Unlock(list[index].lock);
    238    }
    239 
    240 #if 0
    241        printf("wait for threads to be done\n");
    242 #endif
    243    /* Wait for threads to finish */
    244    PR_Lock(exitlock);
    245    while (exitcount < arg) {
    246      PR_WaitCondVar(exitcvar, PR_SecondsToInterval(60));
    247    }
    248    PR_ASSERT(exitcount >= arg);
    249    exitcount -= arg;
    250    PR_Unlock(exitlock);
    251 #if 0
    252        printf("threads ready\n");
    253 #endif
    254  }
    255 
    256  /* Join all the threads */
    257  for (index = 0; index < (arg); index++) {
    258    PR_JoinThread(list[index].thread);
    259  }
    260 
    261  PR_DestroyCondVar(sharedcvar);
    262  PR_DestroyLock(sharedlock);
    263  PR_DestroyCondVar(exitcvar);
    264  PR_DestroyLock(exitlock);
    265 
    266  PR_DELETE(list);
    267 }
    268 
    269 void CondVarTestPUU(void* _arg) {
    270  PRInt32 arg = (PRInt32)_arg;
    271  PRInt32 index, loops;
    272  threadinfo* list;
    273  PRLock* sharedlock;
    274  PRCondVar* sharedcvar;
    275  PRLock* exitlock;
    276  PRCondVar* exitcvar;
    277  PRInt32 *tcount, *saved_tcount;
    278 
    279  exitcount = 0;
    280  list = (threadinfo*)PR_MALLOC(sizeof(threadinfo) * (arg * 4));
    281  saved_tcount = tcount = (PRInt32*)PR_CALLOC(sizeof(*tcount) * (arg * 4));
    282 
    283  sharedlock = PR_NewLock();
    284  sharedcvar = PR_NewCondVar(sharedlock);
    285  exitlock = PR_NewLock();
    286  exitcvar = PR_NewCondVar(exitlock);
    287 
    288  /* Create the threads */
    289  for (index = 0; index < arg;) {
    290    list[index].lock = PR_NewLock();
    291    list[index].cvar = PR_NewCondVar(list[index].lock);
    292    CreateTestThread(&list[index], index, list[index].lock, list[index].cvar,
    293                     count, PR_INTERVAL_NO_TIMEOUT, tcount, exitlock, exitcvar,
    294                     &exitcount, PR_FALSE, PR_LOCAL_THREAD);
    295 
    296    DPRINTF(("CondVarTestPUU: created thread 0x%lx\n", list[index].thread));
    297    index++;
    298    tcount++;
    299  }
    300 
    301  for (loops = 0; loops < count; loops++) {
    302    /* Notify the threads */
    303    for (index = 0; index < (arg); index++) {
    304      PR_Lock(list[index].lock);
    305      (*list[index].tcount)++;
    306      PR_NotifyCondVar(list[index].cvar);
    307      PR_Unlock(list[index].lock);
    308    }
    309 
    310    PR_Lock(exitlock);
    311    /* Wait for threads to finish */
    312    while (exitcount < arg) {
    313      DPRINTF(
    314          ("CondVarTestPUU: thread 0x%lx waiting on exitcvar = 0x%lx cnt = "
    315           "%ld\n",
    316           PR_GetCurrentThread(), exitcvar, exitcount));
    317      PR_WaitCondVar(exitcvar, PR_SecondsToInterval(60));
    318    }
    319    PR_ASSERT(exitcount >= arg);
    320    exitcount -= arg;
    321    PR_Unlock(exitlock);
    322  }
    323 
    324  /* Join all the threads */
    325  for (index = 0; index < (arg); index++) {
    326    DPRINTF(("CondVarTestPUU: joining thread 0x%lx\n", list[index].thread));
    327    PR_JoinThread(list[index].thread);
    328    if (list[index].internal) {
    329      PR_Lock(list[index].lock);
    330      PR_DestroyCondVar(list[index].cvar);
    331      PR_Unlock(list[index].lock);
    332      PR_DestroyLock(list[index].lock);
    333    }
    334  }
    335 
    336  PR_DestroyCondVar(sharedcvar);
    337  PR_DestroyLock(sharedlock);
    338  PR_DestroyCondVar(exitcvar);
    339  PR_DestroyLock(exitlock);
    340 
    341  PR_DELETE(list);
    342  PR_DELETE(saved_tcount);
    343 }
    344 
    345 void CondVarTestPUK(void* _arg) {
    346  PRInt32 arg = (PRInt32)_arg;
    347  PRInt32 index, loops;
    348  threadinfo* list;
    349  PRLock* sharedlock;
    350  PRCondVar* sharedcvar;
    351  PRLock* exitlock;
    352  PRCondVar* exitcvar;
    353  PRInt32 *tcount, *saved_tcount;
    354 
    355  exitcount = 0;
    356  list = (threadinfo*)PR_MALLOC(sizeof(threadinfo) * (arg * 4));
    357  saved_tcount = tcount = (PRInt32*)PR_CALLOC(sizeof(*tcount) * (arg * 4));
    358 
    359  sharedlock = PR_NewLock();
    360  sharedcvar = PR_NewCondVar(sharedlock);
    361  exitlock = PR_NewLock();
    362  exitcvar = PR_NewCondVar(exitlock);
    363 
    364  /* Create the threads */
    365  for (index = 0; index < arg;) {
    366    list[index].lock = PR_NewLock();
    367    list[index].cvar = PR_NewCondVar(list[index].lock);
    368    CreateTestThread(&list[index], index, list[index].lock, list[index].cvar,
    369                     count, PR_INTERVAL_NO_TIMEOUT, tcount, exitlock, exitcvar,
    370                     &exitcount, PR_FALSE, PR_GLOBAL_THREAD);
    371 
    372    index++;
    373    tcount++;
    374  }
    375 
    376  for (loops = 0; loops < count; loops++) {
    377    /* Notify the threads */
    378    for (index = 0; index < (arg); index++) {
    379      PR_Lock(list[index].lock);
    380      (*list[index].tcount)++;
    381      PR_NotifyCondVar(list[index].cvar);
    382      PR_Unlock(list[index].lock);
    383    }
    384 
    385    /* Wait for threads to finish */
    386    PR_Lock(exitlock);
    387    while (exitcount < arg) {
    388      PR_WaitCondVar(exitcvar, PR_SecondsToInterval(60));
    389    }
    390    PR_ASSERT(exitcount >= arg);
    391    exitcount -= arg;
    392    PR_Unlock(exitlock);
    393  }
    394 
    395  /* Join all the threads */
    396  for (index = 0; index < (arg); index++) {
    397    PR_JoinThread(list[index].thread);
    398    if (list[index].internal) {
    399      PR_Lock(list[index].lock);
    400      PR_DestroyCondVar(list[index].cvar);
    401      PR_Unlock(list[index].lock);
    402      PR_DestroyLock(list[index].lock);
    403    }
    404  }
    405 
    406  PR_DestroyCondVar(sharedcvar);
    407  PR_DestroyLock(sharedlock);
    408  PR_DestroyCondVar(exitcvar);
    409  PR_DestroyLock(exitlock);
    410 
    411  PR_DELETE(list);
    412  PR_DELETE(saved_tcount);
    413 }
    414 
    415 void CondVarTest(void* _arg) {
    416  PRInt32 arg = (PRInt32)_arg;
    417  PRInt32 index, loops;
    418  threadinfo* list;
    419  PRLock* sharedlock;
    420  PRCondVar* sharedcvar;
    421  PRLock* exitlock;
    422  PRCondVar* exitcvar;
    423  PRInt32 *ptcount, *saved_ptcount;
    424 
    425  exitcount = 0;
    426  tcount = 0;
    427  list = (threadinfo*)PR_MALLOC(sizeof(threadinfo) * (arg * 4));
    428  saved_ptcount = ptcount = (PRInt32*)PR_CALLOC(sizeof(*ptcount) * (arg * 4));
    429 
    430  sharedlock = PR_NewLock();
    431  sharedcvar = PR_NewCondVar(sharedlock);
    432  exitlock = PR_NewLock();
    433  exitcvar = PR_NewCondVar(exitlock);
    434 
    435  /* Create the threads */
    436  for (index = 0; index < arg * 4;) {
    437    CreateTestThread(&list[index], index, sharedlock, sharedcvar, count,
    438                     PR_INTERVAL_NO_TIMEOUT, &tcount, exitlock, exitcvar,
    439                     &exitcount, PR_TRUE, PR_LOCAL_THREAD);
    440 
    441    index++;
    442    CreateTestThread(&list[index], index, sharedlock, sharedcvar, count,
    443                     PR_INTERVAL_NO_TIMEOUT, &tcount, exitlock, exitcvar,
    444                     &exitcount, PR_TRUE, PR_GLOBAL_THREAD);
    445 
    446    index++;
    447    list[index].lock = PR_NewLock();
    448    list[index].cvar = PR_NewCondVar(list[index].lock);
    449    CreateTestThread(&list[index], index, list[index].lock, list[index].cvar,
    450                     count, PR_INTERVAL_NO_TIMEOUT, ptcount, exitlock, exitcvar,
    451                     &exitcount, PR_FALSE, PR_LOCAL_THREAD);
    452    index++;
    453    ptcount++;
    454    list[index].lock = PR_NewLock();
    455    list[index].cvar = PR_NewCondVar(list[index].lock);
    456    CreateTestThread(&list[index], index, list[index].lock, list[index].cvar,
    457                     count, PR_INTERVAL_NO_TIMEOUT, ptcount, exitlock, exitcvar,
    458                     &exitcount, PR_FALSE, PR_GLOBAL_THREAD);
    459 
    460    index++;
    461    ptcount++;
    462  }
    463 
    464  for (loops = 0; loops < count; loops++) {
    465    /* Notify the threads */
    466    for (index = 0; index < (arg * 4); index++) {
    467      PR_Lock(list[index].lock);
    468      (*list[index].tcount)++;
    469      PR_NotifyCondVar(list[index].cvar);
    470      PR_Unlock(list[index].lock);
    471    }
    472 
    473 #if 0
    474        printf("wait for threads done\n");
    475 #endif
    476 
    477    /* Wait for threads to finish */
    478    PR_Lock(exitlock);
    479    while (exitcount < arg * 4) {
    480      PR_WaitCondVar(exitcvar, PR_SecondsToInterval(60));
    481    }
    482    PR_ASSERT(exitcount >= arg * 4);
    483    exitcount -= arg * 4;
    484    PR_Unlock(exitlock);
    485 #if 0
    486        printf("threads ready\n");
    487 #endif
    488  }
    489 
    490  /* Join all the threads */
    491  for (index = 0; index < (arg * 4); index++) {
    492    PR_JoinThread(list[index].thread);
    493    if (list[index].internal) {
    494      PR_Lock(list[index].lock);
    495      PR_DestroyCondVar(list[index].cvar);
    496      PR_Unlock(list[index].lock);
    497      PR_DestroyLock(list[index].lock);
    498    }
    499  }
    500 
    501  PR_DestroyCondVar(sharedcvar);
    502  PR_DestroyLock(sharedlock);
    503  PR_DestroyCondVar(exitcvar);
    504  PR_DestroyLock(exitlock);
    505 
    506  PR_DELETE(list);
    507  PR_DELETE(saved_ptcount);
    508 }
    509 
    510 void CondVarTimeoutTest(void* _arg) {
    511  PRInt32 arg = (PRInt32)_arg;
    512  PRInt32 index, loops;
    513  threadinfo* list;
    514  PRLock* sharedlock;
    515  PRCondVar* sharedcvar;
    516  PRLock* exitlock;
    517  PRCondVar* exitcvar;
    518 
    519  list = (threadinfo*)PR_MALLOC(sizeof(threadinfo) * (arg * 4));
    520 
    521  sharedlock = PR_NewLock();
    522  sharedcvar = PR_NewCondVar(sharedlock);
    523  exitlock = PR_NewLock();
    524  exitcvar = PR_NewCondVar(exitlock);
    525 
    526  /* Create the threads */
    527  for (index = 0; index < arg * 4;) {
    528    CreateTestThread(&list[index], index, sharedlock, sharedcvar, count,
    529                     PR_MillisecondsToInterval(50), &tcount, exitlock, exitcvar,
    530                     &exitcount, PR_TRUE, PR_LOCAL_THREAD);
    531    index++;
    532    CreateTestThread(&list[index], index, sharedlock, sharedcvar, count,
    533                     PR_MillisecondsToInterval(50), &tcount, exitlock, exitcvar,
    534                     &exitcount, PR_TRUE, PR_GLOBAL_THREAD);
    535    index++;
    536    list[index].lock = PR_NewLock();
    537    list[index].cvar = PR_NewCondVar(list[index].lock);
    538    CreateTestThread(&list[index], index, list[index].lock, list[index].cvar,
    539                     count, PR_MillisecondsToInterval(50), &tcount, exitlock,
    540                     exitcvar, &exitcount, PR_FALSE, PR_LOCAL_THREAD);
    541    index++;
    542 
    543    list[index].lock = PR_NewLock();
    544    list[index].cvar = PR_NewCondVar(list[index].lock);
    545    CreateTestThread(&list[index], index, list[index].lock, list[index].cvar,
    546                     count, PR_MillisecondsToInterval(50), &tcount, exitlock,
    547                     exitcvar, &exitcount, PR_FALSE, PR_GLOBAL_THREAD);
    548 
    549    index++;
    550  }
    551 
    552  for (loops = 0; loops < count; loops++) {
    553    /* Wait for threads to finish */
    554    PR_Lock(exitlock);
    555    while (exitcount < arg * 4) {
    556      PR_WaitCondVar(exitcvar, PR_SecondsToInterval(60));
    557    }
    558    PR_ASSERT(exitcount >= arg * 4);
    559    exitcount -= arg * 4;
    560    PR_Unlock(exitlock);
    561  }
    562 
    563  /* Join all the threads */
    564  for (index = 0; index < (arg * 4); index++) {
    565    PR_JoinThread(list[index].thread);
    566    if (list[index].internal) {
    567      PR_Lock(list[index].lock);
    568      PR_DestroyCondVar(list[index].cvar);
    569      PR_Unlock(list[index].lock);
    570      PR_DestroyLock(list[index].lock);
    571    }
    572  }
    573 
    574  PR_DestroyCondVar(sharedcvar);
    575  PR_DestroyLock(sharedlock);
    576  PR_DestroyCondVar(exitcvar);
    577  PR_DestroyLock(exitlock);
    578 
    579  PR_DELETE(list);
    580 }
    581 
    582 void CondVarMixedTest(void* _arg) {
    583  PRInt32 arg = (PRInt32)_arg;
    584  PRInt32 index, loops;
    585  threadinfo* list;
    586  PRLock* sharedlock;
    587  PRCondVar* sharedcvar;
    588  PRLock* exitlock;
    589  PRCondVar* exitcvar;
    590  PRInt32* ptcount;
    591 
    592  exitcount = 0;
    593  tcount = 0;
    594  list = (threadinfo*)PR_MALLOC(sizeof(threadinfo) * (arg * 4));
    595  ptcount = (PRInt32*)PR_CALLOC(sizeof(*ptcount) * (arg * 4));
    596 
    597  sharedlock = PR_NewLock();
    598  sharedcvar = PR_NewCondVar(sharedlock);
    599  exitlock = PR_NewLock();
    600  exitcvar = PR_NewCondVar(exitlock);
    601 
    602  /* Create the threads */
    603  for (index = 0; index < arg * 4;) {
    604    CreateTestThread(&list[index], index, sharedlock, sharedcvar, count,
    605                     PR_MillisecondsToInterval(50), &tcount, exitlock, exitcvar,
    606                     &exitcount, PR_TRUE, PR_LOCAL_THREAD);
    607    index++;
    608    CreateTestThread(&list[index], index, sharedlock, sharedcvar, count,
    609                     PR_MillisecondsToInterval(50), &tcount, exitlock, exitcvar,
    610                     &exitcount, PR_TRUE, PR_GLOBAL_THREAD);
    611    index++;
    612    list[index].lock = PR_NewLock();
    613    list[index].cvar = PR_NewCondVar(list[index].lock);
    614    CreateTestThread(&list[index], index, list[index].lock, list[index].cvar,
    615                     count, PR_MillisecondsToInterval(50), ptcount, exitlock,
    616                     exitcvar, &exitcount, PR_FALSE, PR_LOCAL_THREAD);
    617    index++;
    618    ptcount++;
    619 
    620    list[index].lock = PR_NewLock();
    621    list[index].cvar = PR_NewCondVar(list[index].lock);
    622    CreateTestThread(&list[index], index, list[index].lock, list[index].cvar,
    623                     count, PR_MillisecondsToInterval(50), ptcount, exitlock,
    624                     exitcvar, &exitcount, PR_FALSE, PR_GLOBAL_THREAD);
    625    index++;
    626    ptcount++;
    627  }
    628 
    629  /* Notify every 3rd thread */
    630  for (loops = 0; loops < count; loops++) {
    631    /* Notify the threads */
    632    for (index = 0; index < (arg * 4); index += 3) {
    633      PR_Lock(list[index].lock);
    634      *list[index].tcount++;
    635      PR_NotifyCondVar(list[index].cvar);
    636      PR_Unlock(list[index].lock);
    637    }
    638    /* Wait for threads to finish */
    639    PR_Lock(exitlock);
    640    while (exitcount < arg * 4) {
    641      PR_WaitCondVar(exitcvar, PR_SecondsToInterval(60));
    642    }
    643    PR_ASSERT(exitcount >= arg * 4);
    644    exitcount -= arg * 4;
    645    PR_Unlock(exitlock);
    646  }
    647 
    648  /* Join all the threads */
    649  for (index = 0; index < (arg * 4); index++) {
    650    PR_JoinThread(list[index].thread);
    651    if (list[index].internal) {
    652      PR_Lock(list[index].lock);
    653      PR_DestroyCondVar(list[index].cvar);
    654      PR_Unlock(list[index].lock);
    655      PR_DestroyLock(list[index].lock);
    656    }
    657  }
    658 
    659  PR_DestroyCondVar(sharedcvar);
    660  PR_DestroyLock(sharedlock);
    661 
    662  PR_DELETE(list);
    663 }
    664 
    665 void CondVarCombinedTest(void* arg) {
    666  PRThread* threads[3];
    667 
    668  threads[0] = PR_CreateThread(PR_USER_THREAD, CondVarTest, (void*)arg,
    669                               PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
    670                               PR_JOINABLE_THREAD, 0);
    671  threads[1] = PR_CreateThread(PR_USER_THREAD, CondVarTimeoutTest, (void*)arg,
    672                               PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
    673                               PR_JOINABLE_THREAD, 0);
    674  threads[2] = PR_CreateThread(PR_USER_THREAD, CondVarMixedTest, (void*)arg,
    675                               PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
    676                               PR_JOINABLE_THREAD, 0);
    677 
    678  PR_JoinThread(threads[0]);
    679  PR_JoinThread(threads[1]);
    680  PR_JoinThread(threads[2]);
    681 }
    682 
    683 /************************************************************************/
    684 
    685 static void Measure(void (*func)(void*), PRInt32 arg, const char* msg) {
    686  PRIntervalTime start, stop;
    687  double d;
    688 
    689  start = PR_IntervalNow();
    690  (*func)((void*)arg);
    691  stop = PR_IntervalNow();
    692 
    693  d = (double)PR_IntervalToMicroseconds(stop - start);
    694 
    695  printf("%40s: %6.2f usec\n", msg, d / count);
    696 }
    697 
    698 static PRIntn PR_CALLBACK RealMain(int argc, char** argv) {
    699  PRInt32 threads, default_threads = DEFAULT_THREADS;
    700  PLOptStatus os;
    701  PLOptState* opt = PL_CreateOptState(argc, argv, "vc:t:");
    702  while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) {
    703    if (PL_OPT_BAD == os) {
    704      continue;
    705    }
    706    switch (opt->option) {
    707      case 'v': /* debug mode */
    708        _debug_on = 1;
    709        break;
    710      case 'c': /* loop counter */
    711        count = atoi(opt->value);
    712        break;
    713      case 't': /* number of threads involved */
    714        default_threads = atoi(opt->value);
    715        break;
    716      default:
    717        break;
    718    }
    719  }
    720  PL_DestroyOptState(opt);
    721 
    722  if (0 == count) {
    723    count = DEFAULT_COUNT;
    724  }
    725  if (0 == default_threads) {
    726    default_threads = DEFAULT_THREADS;
    727  }
    728 
    729  printf(
    730      "\n\
    731 CondVar Test:                                                           \n\
    732                                                                        \n\
    733 Simple test creates several local and global threads; half use a single,\n\
    734 shared condvar, and the other half have their own condvar.  The main    \n\
    735 thread then loops notifying them to wakeup.                             \n\
    736                                                                        \n\
    737 The timeout test is very similar except that the threads are not        \n\
    738 notified.  They will all wakeup on a 1 second timeout.                  \n\
    739                                                                        \n\
    740 The mixed test combines the simple test and the timeout test; every     \n\
    741 third thread is notified, the other threads are expected to timeout     \n\
    742 correctly.                                                              \n\
    743                                                                        \n\
    744 Lastly, the combined test creates a thread for each of the above three  \n\
    745 cases and they all run simultaneously.                                  \n\
    746                                                                        \n\
    747 This test is run with %d, %d, %d, and %d threads of each type.\n\n",
    748      default_threads, default_threads * 2, default_threads * 3,
    749      default_threads * 4);
    750 
    751  PR_SetConcurrency(2);
    752 
    753  for (threads = default_threads; threads < default_threads * 5;
    754       threads += default_threads) {
    755    printf("\n%ld Thread tests\n", threads);
    756    Measure(CondVarTestSUU, threads, "Condvar simple test shared UU");
    757    Measure(CondVarTestSUK, threads, "Condvar simple test shared UK");
    758    Measure(CondVarTestPUU, threads, "Condvar simple test priv UU");
    759    Measure(CondVarTestPUK, threads, "Condvar simple test priv UK");
    760    Measure(CondVarTest, threads, "Condvar simple test All");
    761    Measure(CondVarTimeoutTest, threads, "Condvar timeout test");
    762 #if 0
    763        Measure(CondVarMixedTest, threads,  "Condvar mixed timeout test");
    764        Measure(CondVarCombinedTest, threads, "Combined condvar test");
    765 #endif
    766  }
    767 
    768  printf("PASS\n");
    769 
    770  return 0;
    771 }
    772 
    773 int main(int argc, char** argv) {
    774  PRIntn rv;
    775 
    776  rv = PR_Initialize(RealMain, argc, argv, 0);
    777  return rv;
    778 } /* main */