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 */