tor-browser

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

bug1test.c (5674B)


      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 Attached is a test program that uses the nspr1 to demonstrate a bug
      8 under NT4.0. The fix has already been mentioned (add a ResetEvent just
      9 before leaving the critical section in _PR_CondWait in hwmon.c).
     10 */
     11 
     12 #include "prthread.h"
     13 #include "prtypes.h"
     14 #include "prinit.h"
     15 #include "prmon.h"
     16 #include "prlog.h"
     17 
     18 typedef struct Arg_s {
     19  PRInt32 a, b;
     20 } Arg_t;
     21 
     22 PRMonitor* gMonitor;    // the monitor
     23 PRInt32 gReading;       // number of read locks
     24 PRInt32 gWriteWaiting;  // number of threads waiting for write lock
     25 PRInt32 gReadWaiting;   // number of threads waiting for read lock
     26 
     27 PRInt32 gCounter;  // a counter
     28 
     29 // stats
     30 PRInt32 gReads;          // number of successful reads
     31 PRInt32 gMaxReads;       // max number of simultaneous reads
     32 PRInt32 gMaxWriteWaits;  // max number of writes that waited for read
     33 PRInt32 gMaxReadWaits;   // max number of reads that waited for write wait
     34 
     35 void spin(PRInt32 aDelay) {
     36  PRInt32 index;
     37  PRInt32 delay = aDelay * 1000;
     38 
     39  PR_Sleep(0);
     40 
     41  // randomize delay a bit
     42  delay =
     43      (delay / 2) + (PRInt32)((float)delay * ((float)rand() / (float)RAND_MAX));
     44 
     45  for (index = 0; index < delay * 10; index++)
     46    // consume a bunch of cpu cycles
     47    ;
     48  PR_Sleep(0);
     49 }
     50 
     51 void doWriteThread(void* arg) {
     52  PRInt32 last;
     53  Arg_t* args = (Arg_t*)arg;
     54  PRInt32 aWorkDelay = args->a, aWaitDelay = args->b;
     55  PR_Sleep(0);
     56 
     57  while (1) {
     58    // -- enter write lock
     59    PR_EnterMonitor(gMonitor);
     60 
     61    if (0 < gReading)  // wait for read locks to go away
     62    {
     63      PRIntervalTime fiveSecs = PR_SecondsToInterval(5);
     64 
     65      gWriteWaiting++;
     66      if (gWriteWaiting > gMaxWriteWaits) {  // stats
     67        gMaxWriteWaits = gWriteWaiting;
     68      }
     69      while (0 < gReading) {
     70        PR_Wait(gMonitor, fiveSecs);
     71      }
     72      gWriteWaiting--;
     73    }
     74    // -- write lock entered
     75 
     76    last = gCounter;
     77    gCounter++;
     78 
     79    spin(aWorkDelay);
     80 
     81    PR_ASSERT(gCounter == (last + 1));  // test invariance
     82 
     83    // -- exit write lock
     84    //    if (0 < gReadWaiting)   // notify waiting reads (do it anyway to show
     85    //    off the CondWait bug)
     86    PR_NotifyAll(gMonitor);
     87 
     88    PR_ExitMonitor(gMonitor);
     89    // -- write lock exited
     90 
     91    spin(aWaitDelay);
     92  }
     93 }
     94 
     95 void doReadThread(void* arg) {
     96  PRInt32 last;
     97  Arg_t* args = (Arg_t*)arg;
     98  PRInt32 aWorkDelay = args->a, aWaitDelay = args->b;
     99  PR_Sleep(0);
    100 
    101  while (1) {
    102    // -- enter read lock
    103    PR_EnterMonitor(gMonitor);
    104 
    105    if (0 < gWriteWaiting)  // give up the monitor to waiting writes
    106    {
    107      PRIntervalTime fiveSecs = PR_SecondsToInterval(5);
    108 
    109      gReadWaiting++;
    110      if (gReadWaiting > gMaxReadWaits) {  // stats
    111        gMaxReadWaits = gReadWaiting;
    112      }
    113      while (0 < gWriteWaiting) {
    114        PR_Wait(gMonitor, fiveSecs);
    115      }
    116      gReadWaiting--;
    117    }
    118 
    119    gReading++;
    120 
    121    gReads++;                    // stats
    122    if (gReading > gMaxReads) {  // stats
    123      gMaxReads = gReading;
    124    }
    125 
    126    PR_ExitMonitor(gMonitor);
    127    // -- read lock entered
    128 
    129    last = gCounter;
    130 
    131    spin(aWorkDelay);
    132 
    133    PR_ASSERT(gCounter == last);  // test invariance
    134 
    135    // -- exit read lock
    136    PR_EnterMonitor(gMonitor);  // read unlock
    137    gReading--;
    138 
    139    //    if ((0 == gReading) && (0 < gWriteWaiting))  // notify waiting writes
    140    //    (do it anyway to show off the CondWait bug)
    141    PR_NotifyAll(gMonitor);
    142    PR_ExitMonitor(gMonitor);
    143    // -- read lock exited
    144 
    145    spin(aWaitDelay);
    146  }
    147 }
    148 
    149 void fireThread(char* aName, void (*aProc)(void* arg), Arg_t* aArg) {
    150  PRThread* thread =
    151      PR_CreateThread(PR_USER_THREAD, aProc, aArg, PR_PRIORITY_NORMAL,
    152                      PR_LOCAL_THREAD, PR_UNJOINABLE_THREAD, 0);
    153 }
    154 
    155 int pseudoMain(int argc, char** argv, char* pad) {
    156  PRInt32 lastWriteCount = gCounter;
    157  PRInt32 lastReadCount = gReads;
    158  Arg_t a1 = {500, 250};
    159  Arg_t a2 = {500, 500};
    160  Arg_t a3 = {250, 500};
    161  Arg_t a4 = {750, 250};
    162  Arg_t a5 = {100, 750};
    163  Arg_t a6 = {100, 500};
    164  Arg_t a7 = {100, 750};
    165 
    166  gMonitor = PR_NewMonitor();
    167 
    168  fireThread("R1", doReadThread, &a1);
    169  fireThread("R2", doReadThread, &a2);
    170  fireThread("R3", doReadThread, &a3);
    171  fireThread("R4", doReadThread, &a4);
    172 
    173  fireThread("W1", doWriteThread, &a5);
    174  fireThread("W2", doWriteThread, &a6);
    175  fireThread("W3", doWriteThread, &a7);
    176 
    177  fireThread("R5", doReadThread, &a1);
    178  fireThread("R6", doReadThread, &a2);
    179  fireThread("R7", doReadThread, &a3);
    180  fireThread("R8", doReadThread, &a4);
    181 
    182  fireThread("W4", doWriteThread, &a5);
    183  fireThread("W5", doWriteThread, &a6);
    184  fireThread("W6", doWriteThread, &a7);
    185 
    186  while (1) {
    187    PRInt32 writeCount, readCount;
    188    PRIntervalTime fiveSecs = PR_SecondsToInterval(5);
    189    PR_Sleep(fiveSecs);  // get out of the way
    190 
    191    // print some stats, not threadsafe, informative only
    192    writeCount = gCounter;
    193    readCount = gReads;
    194    printf("\ntick %d writes (+%d), %d reads (+%d) [max %d, %d, %d]",
    195           writeCount, writeCount - lastWriteCount, readCount,
    196           readCount - lastReadCount, gMaxReads, gMaxWriteWaits, gMaxReadWaits);
    197    lastWriteCount = writeCount;
    198    lastReadCount = readCount;
    199    gMaxReads = gMaxWriteWaits = gMaxReadWaits = 0;
    200  }
    201  return 0;
    202 }
    203 
    204 static void padStack(int argc, char** argv) {
    205  char pad[512]; /* Work around bug in nspr on windoze */
    206  pseudoMain(argc, argv, pad);
    207 }
    208 
    209 int main(int argc, char** argv) {
    210  PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
    211  padStack(argc, argv);
    212 }
    213 
    214 /* bug1test.c */