1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* ***** BEGIN LICENSE BLOCK *****
3
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
5
* The contents of this file are subject to the Mozilla Public License Version
6
* 1.1 (the "License"); you may not use this file except in compliance with
7
* the License. You may obtain a copy of the License at
8
* http://www.mozilla.org/MPL/
10
* Software distributed under the License is distributed on an "AS IS" basis,
11
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12
* for the specific language governing rights and limitations under the
15
* The Original Code is the Netscape Portable Runtime (NSPR).
17
* The Initial Developer of the Original Code is
18
* Netscape Communications Corporation.
19
* Portions created by the Initial Developer are Copyright (C) 1998-2000
20
* the Initial Developer. All Rights Reserved.
24
* Alternatively, the contents of this file may be used under the terms of
25
* either the GNU General Public License Version 2 or later (the "GPL"), or
26
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27
* in which case the provisions of the GPL or the LGPL are applicable instead
28
* of those above. If you wish to allow use of your version of this file only
29
* under the terms of either the GPL or the LGPL, and not to allow others to
30
* use your version of this file under the terms of the MPL, indicate your
31
* decision by deleting the provisions above and replace them with the notice
32
* and other provisions required by the GPL or the LGPL. If you do not delete
33
* the provisions above, a recipient may use your version of this file under
34
* the terms of any one of the MPL, the GPL or the LGPL.
36
* ***** END LICENSE BLOCK ***** */
39
Attached is a test program that uses the nspr1 to demonstrate a bug
40
under NT4.0. The fix has already been mentioned (add a ResetEvent just
41
before leaving the critical section in _PR_CondWait in hwmon.c).
55
PRMonitor* gMonitor; // the monitor
56
PRInt32 gReading; // number of read locks
57
PRInt32 gWriteWaiting; // number of threads waiting for write lock
58
PRInt32 gReadWaiting; // number of threads waiting for read lock
60
PRInt32 gCounter; // a counter
63
PRInt32 gReads; // number of successful reads
64
PRInt32 gMaxReads; // max number of simultaneous reads
65
PRInt32 gMaxWriteWaits; // max number of writes that waited for read
66
PRInt32 gMaxReadWaits; // max number of reads that waited for write wait
69
void spin (PRInt32 aDelay)
72
PRInt32 delay = aDelay * 1000;
76
// randomize delay a bit
77
delay = (delay / 2) + (PRInt32)((float)delay *
78
((float)rand () / (float)RAND_MAX));
80
for (index = 0; index < delay * 10; index++)
81
// consume a bunch of cpu cycles
86
void doWriteThread (void* arg)
89
Arg_t *args = (Arg_t*)arg;
90
PRInt32 aWorkDelay = args->a, aWaitDelay = args->b;
95
// -- enter write lock
96
PR_EnterMonitor (gMonitor);
98
if (0 < gReading) // wait for read locks to go away
100
PRIntervalTime fiveSecs = PR_SecondsToInterval(5);
103
if (gWriteWaiting > gMaxWriteWaits) // stats
104
gMaxWriteWaits = gWriteWaiting;
106
PR_Wait (gMonitor, fiveSecs);
109
// -- write lock entered
116
PR_ASSERT (gCounter == (last + 1)); // test invariance
118
// -- exit write lock
119
// if (0 < gReadWaiting) // notify waiting reads (do it anyway to show off the CondWait bug)
120
PR_NotifyAll (gMonitor);
122
PR_ExitMonitor (gMonitor);
123
// -- write lock exited
129
void doReadThread (void* arg)
132
Arg_t *args = (Arg_t*)arg;
133
PRInt32 aWorkDelay = args->a, aWaitDelay = args->b;
138
// -- enter read lock
139
PR_EnterMonitor (gMonitor);
141
if (0 < gWriteWaiting) // give up the monitor to waiting writes
143
PRIntervalTime fiveSecs = PR_SecondsToInterval(5);
146
if (gReadWaiting > gMaxReadWaits) // stats
147
gMaxReadWaits = gReadWaiting;
148
while (0 < gWriteWaiting)
149
PR_Wait (gMonitor, fiveSecs);
156
if (gReading > gMaxReads) // stats
157
gMaxReads = gReading;
159
PR_ExitMonitor (gMonitor);
160
// -- read lock entered
166
PR_ASSERT (gCounter == last); // test invariance
169
PR_EnterMonitor (gMonitor); // read unlock
172
// if ((0 == gReading) && (0 < gWriteWaiting)) // notify waiting writes (do it anyway to show off the CondWait bug)
173
PR_NotifyAll (gMonitor);
174
PR_ExitMonitor (gMonitor);
175
// -- read lock exited
183
char* aName, void (*aProc)(void *arg), Arg_t *aArg)
185
PRThread *thread = PR_CreateThread(
186
PR_USER_THREAD, aProc, aArg, PR_PRIORITY_NORMAL,
187
PR_LOCAL_THREAD, PR_UNJOINABLE_THREAD, 0);
190
int pseudoMain (int argc, char** argv, char *pad)
192
PRInt32 lastWriteCount = gCounter;
193
PRInt32 lastReadCount = gReads;
194
Arg_t a1 = {500, 250};
195
Arg_t a2 = {500, 500};
196
Arg_t a3 = {250, 500};
197
Arg_t a4 = {750, 250};
198
Arg_t a5 = {100, 750};
199
Arg_t a6 = {100, 500};
200
Arg_t a7 = {100, 750};
202
gMonitor = PR_NewMonitor ();
204
fireThread ("R1", doReadThread, &a1);
205
fireThread ("R2", doReadThread, &a2);
206
fireThread ("R3", doReadThread, &a3);
207
fireThread ("R4", doReadThread, &a4);
209
fireThread ("W1", doWriteThread, &a5);
210
fireThread ("W2", doWriteThread, &a6);
211
fireThread ("W3", doWriteThread, &a7);
213
fireThread ("R5", doReadThread, &a1);
214
fireThread ("R6", doReadThread, &a2);
215
fireThread ("R7", doReadThread, &a3);
216
fireThread ("R8", doReadThread, &a4);
218
fireThread ("W4", doWriteThread, &a5);
219
fireThread ("W5", doWriteThread, &a6);
220
fireThread ("W6", doWriteThread, &a7);
224
PRInt32 writeCount, readCount;
225
PRIntervalTime fiveSecs = PR_SecondsToInterval(5);
226
PR_Sleep (fiveSecs); // get out of the way
228
// print some stats, not threadsafe, informative only
229
writeCount = gCounter;
231
printf ("\ntick %d writes (+%d), %d reads (+%d) [max %d, %d, %d]",
232
writeCount, writeCount - lastWriteCount,
233
readCount, readCount - lastReadCount,
234
gMaxReads, gMaxWriteWaits, gMaxReadWaits);
235
lastWriteCount = writeCount;
236
lastReadCount = readCount;
237
gMaxReads = gMaxWriteWaits = gMaxReadWaits = 0;
243
static void padStack (int argc, char** argv)
245
char pad[512]; /* Work around bug in nspr on windoze */
246
pseudoMain (argc, argv, pad);
249
void main (int argc, char **argv)
251
PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
253
padStack (argc, argv);