nsprpub/pr/tests/bug1test.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/nsprpub/pr/tests/bug1test.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,225 @@
     1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +/*
    1.10 +Attached is a test program that uses the nspr1 to demonstrate a bug
    1.11 +under NT4.0. The fix has already been mentioned (add a ResetEvent just
    1.12 +before leaving the critical section in _PR_CondWait in hwmon.c).
    1.13 +*/
    1.14 +
    1.15 +#include "prthread.h"
    1.16 +#include "prtypes.h"
    1.17 +#include "prinit.h"
    1.18 +#include "prmon.h"
    1.19 +#include "prlog.h"
    1.20 +
    1.21 +typedef struct Arg_s
    1.22 +{
    1.23 +	PRInt32 a, b;
    1.24 +} Arg_t;
    1.25 +
    1.26 +PRMonitor*  gMonitor;       // the monitor
    1.27 +PRInt32     gReading;       // number of read locks
    1.28 +PRInt32     gWriteWaiting;  // number of threads waiting for write lock
    1.29 +PRInt32     gReadWaiting;   // number of threads waiting for read lock
    1.30 +
    1.31 +PRInt32     gCounter;       // a counter
    1.32 +
    1.33 +                            // stats
    1.34 +PRInt32     gReads;         // number of successful reads
    1.35 +PRInt32     gMaxReads;      // max number of simultaneous reads
    1.36 +PRInt32     gMaxWriteWaits; // max number of writes that waited for read
    1.37 +PRInt32     gMaxReadWaits;  // max number of reads that waited for write wait
    1.38 +
    1.39 +
    1.40 +void spin (PRInt32 aDelay)
    1.41 +{
    1.42 +  PRInt32 index;
    1.43 +  PRInt32 delay = aDelay * 1000;
    1.44 +
    1.45 +  PR_Sleep(0);
    1.46 +
    1.47 +  // randomize delay a bit
    1.48 +  delay = (delay / 2) + (PRInt32)((float)delay *
    1.49 +	  ((float)rand () / (float)RAND_MAX));
    1.50 +
    1.51 +  for (index = 0; index < delay * 10; index++)
    1.52 +	  // consume a bunch of cpu cycles
    1.53 +    ;
    1.54 +  PR_Sleep(0); 
    1.55 +}
    1.56 +
    1.57 +void  doWriteThread (void* arg)
    1.58 +{
    1.59 +  PRInt32 last;
    1.60 +  Arg_t *args = (Arg_t*)arg;
    1.61 +  PRInt32 aWorkDelay = args->a, aWaitDelay = args->b;
    1.62 +  PR_Sleep(0);
    1.63 +
    1.64 +  while (1)
    1.65 +  {
    1.66 +    // -- enter write lock
    1.67 +    PR_EnterMonitor (gMonitor);
    1.68 +
    1.69 +    if (0 < gReading)     // wait for read locks to go away
    1.70 +    {
    1.71 +      PRIntervalTime fiveSecs = PR_SecondsToInterval(5);
    1.72 +
    1.73 +      gWriteWaiting++;
    1.74 +      if (gWriteWaiting > gMaxWriteWaits) // stats
    1.75 +        gMaxWriteWaits = gWriteWaiting;
    1.76 +      while (0 < gReading)
    1.77 +        PR_Wait (gMonitor, fiveSecs);
    1.78 +      gWriteWaiting--;
    1.79 +    }
    1.80 +    // -- write lock entered
    1.81 +
    1.82 +    last = gCounter;
    1.83 +    gCounter++;
    1.84 +
    1.85 +    spin (aWorkDelay);
    1.86 +
    1.87 +    PR_ASSERT (gCounter == (last + 1)); // test invariance
    1.88 +
    1.89 +    // -- exit write lock        
    1.90 +//    if (0 < gReadWaiting)   // notify waiting reads (do it anyway to show off the CondWait bug)
    1.91 +      PR_NotifyAll (gMonitor);
    1.92 +
    1.93 +    PR_ExitMonitor (gMonitor);
    1.94 +    // -- write lock exited
    1.95 +
    1.96 +    spin (aWaitDelay);
    1.97 +  }
    1.98 +}
    1.99 +
   1.100 +void  doReadThread (void* arg)
   1.101 +{
   1.102 +  PRInt32 last;
   1.103 +  Arg_t *args = (Arg_t*)arg;
   1.104 +  PRInt32 aWorkDelay = args->a, aWaitDelay = args->b;
   1.105 +  PR_Sleep(0);
   1.106 +
   1.107 +  while (1)
   1.108 +  {
   1.109 +    // -- enter read lock
   1.110 +    PR_EnterMonitor (gMonitor); 
   1.111 +
   1.112 +    if (0 < gWriteWaiting)  // give up the monitor to waiting writes
   1.113 +    {
   1.114 +      PRIntervalTime fiveSecs = PR_SecondsToInterval(5);
   1.115 +
   1.116 +      gReadWaiting++;
   1.117 +      if (gReadWaiting > gMaxReadWaits) // stats
   1.118 +        gMaxReadWaits = gReadWaiting;
   1.119 +      while (0 < gWriteWaiting)
   1.120 +        PR_Wait (gMonitor, fiveSecs);
   1.121 +      gReadWaiting--;
   1.122 +    }
   1.123 +
   1.124 +    gReading++;
   1.125 +
   1.126 +    gReads++;   // stats
   1.127 +    if (gReading > gMaxReads) // stats
   1.128 +      gMaxReads = gReading;
   1.129 +
   1.130 +    PR_ExitMonitor (gMonitor);
   1.131 +    // -- read lock entered
   1.132 +
   1.133 +    last = gCounter;
   1.134 +
   1.135 +    spin (aWorkDelay);
   1.136 +
   1.137 +    PR_ASSERT (gCounter == last); // test invariance
   1.138 +
   1.139 +    // -- exit read lock
   1.140 +    PR_EnterMonitor (gMonitor);  // read unlock
   1.141 +    gReading--;
   1.142 +
   1.143 +//    if ((0 == gReading) && (0 < gWriteWaiting))  // notify waiting writes  (do it anyway to show off the CondWait bug)
   1.144 +      PR_NotifyAll (gMonitor);
   1.145 +    PR_ExitMonitor (gMonitor);
   1.146 +    // -- read lock exited
   1.147 +
   1.148 +    spin (aWaitDelay);
   1.149 +  }
   1.150 +}
   1.151 +
   1.152 +
   1.153 +void fireThread (
   1.154 +    char* aName, void (*aProc)(void *arg), Arg_t *aArg)
   1.155 +{
   1.156 +  PRThread *thread = PR_CreateThread(
   1.157 +	  PR_USER_THREAD, aProc, aArg, PR_PRIORITY_NORMAL,
   1.158 +	  PR_LOCAL_THREAD, PR_UNJOINABLE_THREAD, 0);
   1.159 +}
   1.160 +
   1.161 +int pseudoMain (int argc, char** argv, char *pad)
   1.162 +{
   1.163 +  PRInt32 lastWriteCount  = gCounter;
   1.164 +  PRInt32 lastReadCount   = gReads;
   1.165 +  Arg_t a1 = {500, 250};
   1.166 +  Arg_t a2 = {500, 500};
   1.167 +  Arg_t a3 = {250, 500};
   1.168 +  Arg_t a4 = {750, 250};
   1.169 +  Arg_t a5 = {100, 750};
   1.170 +  Arg_t a6 = {100, 500};
   1.171 +  Arg_t a7 = {100, 750};
   1.172 +
   1.173 +  gMonitor = PR_NewMonitor ();
   1.174 +
   1.175 +  fireThread ("R1", doReadThread,   &a1);
   1.176 +  fireThread ("R2", doReadThread,   &a2);
   1.177 +  fireThread ("R3", doReadThread,   &a3);
   1.178 +  fireThread ("R4", doReadThread,   &a4);
   1.179 +
   1.180 +  fireThread ("W1", doWriteThread,  &a5);
   1.181 +  fireThread ("W2", doWriteThread,  &a6);
   1.182 +  fireThread ("W3", doWriteThread,  &a7);
   1.183 +
   1.184 +  fireThread ("R5", doReadThread,   &a1);
   1.185 +  fireThread ("R6", doReadThread,   &a2);
   1.186 +  fireThread ("R7", doReadThread,   &a3);
   1.187 +  fireThread ("R8", doReadThread,   &a4);
   1.188 +
   1.189 +  fireThread ("W4", doWriteThread,  &a5);
   1.190 +  fireThread ("W5", doWriteThread,  &a6);
   1.191 +  fireThread ("W6", doWriteThread,  &a7);
   1.192 +  
   1.193 +  while (1)
   1.194 +  {
   1.195 +	PRInt32 writeCount, readCount;
   1.196 +    PRIntervalTime fiveSecs = PR_SecondsToInterval(5);
   1.197 +    PR_Sleep (fiveSecs);  // get out of the way
   1.198 +
   1.199 +    // print some stats, not threadsafe, informative only
   1.200 +    writeCount = gCounter;
   1.201 +    readCount   = gReads;
   1.202 +    printf ("\ntick %d writes (+%d), %d reads (+%d) [max %d, %d, %d]", 
   1.203 +            writeCount, writeCount - lastWriteCount,
   1.204 +            readCount, readCount - lastReadCount, 
   1.205 +            gMaxReads, gMaxWriteWaits, gMaxReadWaits);
   1.206 +    lastWriteCount = writeCount;
   1.207 +    lastReadCount = readCount;
   1.208 +    gMaxReads = gMaxWriteWaits = gMaxReadWaits = 0;
   1.209 +  }
   1.210 +  return 0;
   1.211 +}
   1.212 +
   1.213 +
   1.214 +static void padStack (int argc, char** argv)
   1.215 +{
   1.216 +  char pad[512];      /* Work around bug in nspr on windoze */
   1.217 +  pseudoMain (argc, argv, pad);
   1.218 +}
   1.219 +
   1.220 +int main(int argc, char **argv)
   1.221 +{
   1.222 +  PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
   1.223 +  PR_STDIO_INIT();
   1.224 +  padStack (argc, argv);
   1.225 +}
   1.226 +
   1.227 +
   1.228 +/* bug1test.c */

mercurial