home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / nsprpub / pr / tests / bug1test.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  6.3 KB  |  239 lines

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