Back to index

lightning-sunbird  0.9+nobinonly
bug1test.c
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is the Netscape Portable Runtime (NSPR).
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998-2000
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 /*
00039 Attached is a test program that uses the nspr1 to demonstrate a bug
00040 under NT4.0. The fix has already been mentioned (add a ResetEvent just
00041 before leaving the critical section in _PR_CondWait in hwmon.c).
00042 */
00043 
00044 #include "prthread.h"
00045 #include "prtypes.h"
00046 #include "prinit.h"
00047 #include "prmon.h"
00048 #include "prlog.h"
00049 
00050 typedef struct Arg_s
00051 {
00052        PRInt32 a, b;
00053 } Arg_t;
00054 
00055 PRMonitor*  gMonitor;       // the monitor
00056 PRInt32     gReading;       // number of read locks
00057 PRInt32     gWriteWaiting;  // number of threads waiting for write lock
00058 PRInt32     gReadWaiting;   // number of threads waiting for read lock
00059 
00060 PRInt32     gCounter;       // a counter
00061 
00062                             // stats
00063 PRInt32     gReads;         // number of successful reads
00064 PRInt32     gMaxReads;      // max number of simultaneous reads
00065 PRInt32     gMaxWriteWaits; // max number of writes that waited for read
00066 PRInt32     gMaxReadWaits;  // max number of reads that waited for write wait
00067 
00068 
00069 void spin (PRInt32 aDelay)
00070 {
00071   PRInt32 index;
00072   PRInt32 delay = aDelay * 1000;
00073 
00074   PR_Sleep(0);
00075 
00076   // randomize delay a bit
00077   delay = (delay / 2) + (PRInt32)((float)delay *
00078          ((float)rand () / (float)RAND_MAX));
00079 
00080   for (index = 0; index < delay * 10; index++)
00081          // consume a bunch of cpu cycles
00082     ;
00083   PR_Sleep(0); 
00084 }
00085 
00086 void  doWriteThread (void* arg)
00087 {
00088   PRInt32 last;
00089   Arg_t *args = (Arg_t*)arg;
00090   PRInt32 aWorkDelay = args->a, aWaitDelay = args->b;
00091   PR_Sleep(0);
00092 
00093   while (1)
00094   {
00095     // -- enter write lock
00096     PR_EnterMonitor (gMonitor);
00097 
00098     if (0 < gReading)     // wait for read locks to go away
00099     {
00100       PRIntervalTime fiveSecs = PR_SecondsToInterval(5);
00101 
00102       gWriteWaiting++;
00103       if (gWriteWaiting > gMaxWriteWaits) // stats
00104         gMaxWriteWaits = gWriteWaiting;
00105       while (0 < gReading)
00106         PR_Wait (gMonitor, fiveSecs);
00107       gWriteWaiting--;
00108     }
00109     // -- write lock entered
00110 
00111     last = gCounter;
00112     gCounter++;
00113 
00114     spin (aWorkDelay);
00115 
00116     PR_ASSERT (gCounter == (last + 1)); // test invariance
00117 
00118     // -- exit write lock        
00119 //    if (0 < gReadWaiting)   // notify waiting reads (do it anyway to show off the CondWait bug)
00120       PR_NotifyAll (gMonitor);
00121 
00122     PR_ExitMonitor (gMonitor);
00123     // -- write lock exited
00124 
00125     spin (aWaitDelay);
00126   }
00127 }
00128 
00129 void  doReadThread (void* arg)
00130 {
00131   PRInt32 last;
00132   Arg_t *args = (Arg_t*)arg;
00133   PRInt32 aWorkDelay = args->a, aWaitDelay = args->b;
00134   PR_Sleep(0);
00135 
00136   while (1)
00137   {
00138     // -- enter read lock
00139     PR_EnterMonitor (gMonitor); 
00140 
00141     if (0 < gWriteWaiting)  // give up the monitor to waiting writes
00142     {
00143       PRIntervalTime fiveSecs = PR_SecondsToInterval(5);
00144 
00145       gReadWaiting++;
00146       if (gReadWaiting > gMaxReadWaits) // stats
00147         gMaxReadWaits = gReadWaiting;
00148       while (0 < gWriteWaiting)
00149         PR_Wait (gMonitor, fiveSecs);
00150       gReadWaiting--;
00151     }
00152 
00153     gReading++;
00154 
00155     gReads++;   // stats
00156     if (gReading > gMaxReads) // stats
00157       gMaxReads = gReading;
00158 
00159     PR_ExitMonitor (gMonitor);
00160     // -- read lock entered
00161 
00162     last = gCounter;
00163 
00164     spin (aWorkDelay);
00165 
00166     PR_ASSERT (gCounter == last); // test invariance
00167 
00168     // -- exit read lock
00169     PR_EnterMonitor (gMonitor);  // read unlock
00170     gReading--;
00171 
00172 //    if ((0 == gReading) && (0 < gWriteWaiting))  // notify waiting writes  (do it anyway to show off the CondWait bug)
00173       PR_NotifyAll (gMonitor);
00174     PR_ExitMonitor (gMonitor);
00175     // -- read lock exited
00176 
00177     spin (aWaitDelay);
00178   }
00179 }
00180 
00181 
00182 void fireThread (
00183     char* aName, void (*aProc)(void *arg), Arg_t *aArg)
00184 {
00185   PRThread *thread = PR_CreateThread(
00186          PR_USER_THREAD, aProc, aArg, PR_PRIORITY_NORMAL,
00187          PR_LOCAL_THREAD, PR_UNJOINABLE_THREAD, 0);
00188 }
00189 
00190 int pseudoMain (int argc, char** argv, char *pad)
00191 {
00192   PRInt32 lastWriteCount  = gCounter;
00193   PRInt32 lastReadCount   = gReads;
00194   Arg_t a1 = {500, 250};
00195   Arg_t a2 = {500, 500};
00196   Arg_t a3 = {250, 500};
00197   Arg_t a4 = {750, 250};
00198   Arg_t a5 = {100, 750};
00199   Arg_t a6 = {100, 500};
00200   Arg_t a7 = {100, 750};
00201 
00202   gMonitor = PR_NewMonitor ();
00203 
00204   fireThread ("R1", doReadThread,   &a1);
00205   fireThread ("R2", doReadThread,   &a2);
00206   fireThread ("R3", doReadThread,   &a3);
00207   fireThread ("R4", doReadThread,   &a4);
00208 
00209   fireThread ("W1", doWriteThread,  &a5);
00210   fireThread ("W2", doWriteThread,  &a6);
00211   fireThread ("W3", doWriteThread,  &a7);
00212 
00213   fireThread ("R5", doReadThread,   &a1);
00214   fireThread ("R6", doReadThread,   &a2);
00215   fireThread ("R7", doReadThread,   &a3);
00216   fireThread ("R8", doReadThread,   &a4);
00217 
00218   fireThread ("W4", doWriteThread,  &a5);
00219   fireThread ("W5", doWriteThread,  &a6);
00220   fireThread ("W6", doWriteThread,  &a7);
00221   
00222   while (1)
00223   {
00224        PRInt32 writeCount, readCount;
00225     PRIntervalTime fiveSecs = PR_SecondsToInterval(5);
00226     PR_Sleep (fiveSecs);  // get out of the way
00227 
00228     // print some stats, not threadsafe, informative only
00229     writeCount = gCounter;
00230     readCount   = gReads;
00231     printf ("\ntick %d writes (+%d), %d reads (+%d) [max %d, %d, %d]", 
00232             writeCount, writeCount - lastWriteCount,
00233             readCount, readCount - lastReadCount, 
00234             gMaxReads, gMaxWriteWaits, gMaxReadWaits);
00235     lastWriteCount = writeCount;
00236     lastReadCount = readCount;
00237     gMaxReads = gMaxWriteWaits = gMaxReadWaits = 0;
00238   }
00239   return 0;
00240 }
00241 
00242 
00243 static void padStack (int argc, char** argv)
00244 {
00245   char pad[512];      /* Work around bug in nspr on windoze */
00246   pseudoMain (argc, argv, pad);
00247 }
00248 
00249 void main (int argc, char **argv)
00250 {
00251   PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
00252   PR_STDIO_INIT();
00253   padStack (argc, argv);
00254 }
00255 
00256 
00257 /* bug1test.c */