nsprpub/pr/tests/bug1test.c

Fri, 16 Jan 2015 18:13:44 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 18:13:44 +0100
branch
TOR_BUG_9701
changeset 14
925c144e1f1f
permissions
-rw-r--r--

Integrate suggestion from review to improve consistency with existing code.

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

mercurial