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/. */
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).
23 PRMonitor
* gMonitor
; // the monitor
24 PRInt32 gReading
; // number of read locks
25 PRInt32 gWriteWaiting
; // number of threads waiting for write lock
26 PRInt32 gReadWaiting
; // number of threads waiting for read lock
28 PRInt32 gCounter
; // a counter
31 PRInt32 gReads
; // number of successful reads
32 PRInt32 gMaxReads
; // max number of simultaneous reads
33 PRInt32 gMaxWriteWaits
; // max number of writes that waited for read
34 PRInt32 gMaxReadWaits
; // max number of reads that waited for write wait
37 void spin (PRInt32 aDelay
)
40 PRInt32 delay
= aDelay
* 1000;
44 // randomize delay a bit
45 delay
= (delay
/ 2) + (PRInt32
)((float)delay
*
46 ((float)rand () / (float)RAND_MAX
));
48 for (index
= 0; index
< delay
* 10; index
++)
49 // consume a bunch of cpu cycles
54 void doWriteThread (void* arg
)
57 Arg_t
*args
= (Arg_t
*)arg
;
58 PRInt32 aWorkDelay
= args
->a
, aWaitDelay
= args
->b
;
63 // -- enter write lock
64 PR_EnterMonitor (gMonitor
);
66 if (0 < gReading
) // wait for read locks to go away
68 PRIntervalTime fiveSecs
= PR_SecondsToInterval(5);
71 if (gWriteWaiting
> gMaxWriteWaits
) // stats
72 gMaxWriteWaits
= gWriteWaiting
;
74 PR_Wait (gMonitor
, fiveSecs
);
77 // -- write lock entered
84 PR_ASSERT (gCounter
== (last
+ 1)); // test invariance
87 // if (0 < gReadWaiting) // notify waiting reads (do it anyway to show off the CondWait bug)
88 PR_NotifyAll (gMonitor
);
90 PR_ExitMonitor (gMonitor
);
91 // -- write lock exited
97 void doReadThread (void* arg
)
100 Arg_t
*args
= (Arg_t
*)arg
;
101 PRInt32 aWorkDelay
= args
->a
, aWaitDelay
= args
->b
;
106 // -- enter read lock
107 PR_EnterMonitor (gMonitor
);
109 if (0 < gWriteWaiting
) // give up the monitor to waiting writes
111 PRIntervalTime fiveSecs
= PR_SecondsToInterval(5);
114 if (gReadWaiting
> gMaxReadWaits
) // stats
115 gMaxReadWaits
= gReadWaiting
;
116 while (0 < gWriteWaiting
)
117 PR_Wait (gMonitor
, fiveSecs
);
124 if (gReading
> gMaxReads
) // stats
125 gMaxReads
= gReading
;
127 PR_ExitMonitor (gMonitor
);
128 // -- read lock entered
134 PR_ASSERT (gCounter
== last
); // test invariance
137 PR_EnterMonitor (gMonitor
); // read unlock
140 // if ((0 == gReading) && (0 < gWriteWaiting)) // notify waiting writes (do it anyway to show off the CondWait bug)
141 PR_NotifyAll (gMonitor
);
142 PR_ExitMonitor (gMonitor
);
143 // -- read lock exited
151 char* aName
, void (*aProc
)(void *arg
), Arg_t
*aArg
)
153 PRThread
*thread
= PR_CreateThread(
154 PR_USER_THREAD
, aProc
, aArg
, PR_PRIORITY_NORMAL
,
155 PR_LOCAL_THREAD
, PR_UNJOINABLE_THREAD
, 0);
158 int pseudoMain (int argc
, char** argv
, char *pad
)
160 PRInt32 lastWriteCount
= gCounter
;
161 PRInt32 lastReadCount
= gReads
;
162 Arg_t a1
= {500, 250};
163 Arg_t a2
= {500, 500};
164 Arg_t a3
= {250, 500};
165 Arg_t a4
= {750, 250};
166 Arg_t a5
= {100, 750};
167 Arg_t a6
= {100, 500};
168 Arg_t a7
= {100, 750};
170 gMonitor
= PR_NewMonitor ();
172 fireThread ("R1", doReadThread
, &a1
);
173 fireThread ("R2", doReadThread
, &a2
);
174 fireThread ("R3", doReadThread
, &a3
);
175 fireThread ("R4", doReadThread
, &a4
);
177 fireThread ("W1", doWriteThread
, &a5
);
178 fireThread ("W2", doWriteThread
, &a6
);
179 fireThread ("W3", doWriteThread
, &a7
);
181 fireThread ("R5", doReadThread
, &a1
);
182 fireThread ("R6", doReadThread
, &a2
);
183 fireThread ("R7", doReadThread
, &a3
);
184 fireThread ("R8", doReadThread
, &a4
);
186 fireThread ("W4", doWriteThread
, &a5
);
187 fireThread ("W5", doWriteThread
, &a6
);
188 fireThread ("W6", doWriteThread
, &a7
);
192 PRInt32 writeCount
, readCount
;
193 PRIntervalTime fiveSecs
= PR_SecondsToInterval(5);
194 PR_Sleep (fiveSecs
); // get out of the way
196 // print some stats, not threadsafe, informative only
197 writeCount
= gCounter
;
199 printf ("\ntick %d writes (+%d), %d reads (+%d) [max %d, %d, %d]",
200 writeCount
, writeCount
- lastWriteCount
,
201 readCount
, readCount
- lastReadCount
,
202 gMaxReads
, gMaxWriteWaits
, gMaxReadWaits
);
203 lastWriteCount
= writeCount
;
204 lastReadCount
= readCount
;
205 gMaxReads
= gMaxWriteWaits
= gMaxReadWaits
= 0;
211 static void padStack (int argc
, char** argv
)
213 char pad
[512]; /* Work around bug in nspr on windoze */
214 pseudoMain (argc
, argv
, pad
);
217 int main(int argc
, char **argv
)
219 PR_Init(PR_USER_THREAD
, PR_PRIORITY_NORMAL
, 0);
221 padStack (argc
, argv
);