bug1test.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  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/. */
  5. /*
  6. Attached is a test program that uses the nspr1 to demonstrate a bug
  7. under NT4.0. The fix has already been mentioned (add a ResetEvent just
  8. before leaving the critical section in _PR_CondWait in hwmon.c).
  9. */
  10. #include "prthread.h"
  11. #include "prtypes.h"
  12. #include "prinit.h"
  13. #include "prmon.h"
  14. #include "prlog.h"
  15. typedef struct Arg_s
  16. {
  17. PRInt32 a, b;
  18. } Arg_t;
  19. PRMonitor* gMonitor; // the monitor
  20. PRInt32 gReading; // number of read locks
  21. PRInt32 gWriteWaiting; // number of threads waiting for write lock
  22. PRInt32 gReadWaiting; // number of threads waiting for read lock
  23. PRInt32 gCounter; // a counter
  24. // stats
  25. PRInt32 gReads; // number of successful reads
  26. PRInt32 gMaxReads; // max number of simultaneous reads
  27. PRInt32 gMaxWriteWaits; // max number of writes that waited for read
  28. PRInt32 gMaxReadWaits; // max number of reads that waited for write wait
  29. void spin (PRInt32 aDelay)
  30. {
  31. PRInt32 index;
  32. PRInt32 delay = aDelay * 1000;
  33. PR_Sleep(0);
  34. // randomize delay a bit
  35. delay = (delay / 2) + (PRInt32)((float)delay *
  36. ((float)rand () / (float)RAND_MAX));
  37. for (index = 0; index < delay * 10; index++)
  38. // consume a bunch of cpu cycles
  39. ;
  40. PR_Sleep(0);
  41. }
  42. void doWriteThread (void* arg)
  43. {
  44. PRInt32 last;
  45. Arg_t *args = (Arg_t*)arg;
  46. PRInt32 aWorkDelay = args->a, aWaitDelay = args->b;
  47. PR_Sleep(0);
  48. while (1)
  49. {
  50. // -- enter write lock
  51. PR_EnterMonitor (gMonitor);
  52. if (0 < gReading) // wait for read locks to go away
  53. {
  54. PRIntervalTime fiveSecs = PR_SecondsToInterval(5);
  55. gWriteWaiting++;
  56. if (gWriteWaiting > gMaxWriteWaits) { // stats
  57. gMaxWriteWaits = gWriteWaiting;
  58. }
  59. while (0 < gReading) {
  60. PR_Wait (gMonitor, fiveSecs);
  61. }
  62. gWriteWaiting--;
  63. }
  64. // -- write lock entered
  65. last = gCounter;
  66. gCounter++;
  67. spin (aWorkDelay);
  68. PR_ASSERT (gCounter == (last + 1)); // test invariance
  69. // -- exit write lock
  70. // if (0 < gReadWaiting) // notify waiting reads (do it anyway to show off the CondWait bug)
  71. PR_NotifyAll (gMonitor);
  72. PR_ExitMonitor (gMonitor);
  73. // -- write lock exited
  74. spin (aWaitDelay);
  75. }
  76. }
  77. void doReadThread (void* arg)
  78. {
  79. PRInt32 last;
  80. Arg_t *args = (Arg_t*)arg;
  81. PRInt32 aWorkDelay = args->a, aWaitDelay = args->b;
  82. PR_Sleep(0);
  83. while (1)
  84. {
  85. // -- enter read lock
  86. PR_EnterMonitor (gMonitor);
  87. if (0 < gWriteWaiting) // give up the monitor to waiting writes
  88. {
  89. PRIntervalTime fiveSecs = PR_SecondsToInterval(5);
  90. gReadWaiting++;
  91. if (gReadWaiting > gMaxReadWaits) { // stats
  92. gMaxReadWaits = gReadWaiting;
  93. }
  94. while (0 < gWriteWaiting) {
  95. PR_Wait (gMonitor, fiveSecs);
  96. }
  97. gReadWaiting--;
  98. }
  99. gReading++;
  100. gReads++; // stats
  101. if (gReading > gMaxReads) { // stats
  102. gMaxReads = gReading;
  103. }
  104. PR_ExitMonitor (gMonitor);
  105. // -- read lock entered
  106. last = gCounter;
  107. spin (aWorkDelay);
  108. PR_ASSERT (gCounter == last); // test invariance
  109. // -- exit read lock
  110. PR_EnterMonitor (gMonitor); // read unlock
  111. gReading--;
  112. // if ((0 == gReading) && (0 < gWriteWaiting)) // notify waiting writes (do it anyway to show off the CondWait bug)
  113. PR_NotifyAll (gMonitor);
  114. PR_ExitMonitor (gMonitor);
  115. // -- read lock exited
  116. spin (aWaitDelay);
  117. }
  118. }
  119. void fireThread (
  120. char* aName, void (*aProc)(void *arg), Arg_t *aArg)
  121. {
  122. PRThread *thread = PR_CreateThread(
  123. PR_USER_THREAD, aProc, aArg, PR_PRIORITY_NORMAL,
  124. PR_LOCAL_THREAD, PR_UNJOINABLE_THREAD, 0);
  125. }
  126. int pseudoMain (int argc, char** argv, char *pad)
  127. {
  128. PRInt32 lastWriteCount = gCounter;
  129. PRInt32 lastReadCount = gReads;
  130. Arg_t a1 = {500, 250};
  131. Arg_t a2 = {500, 500};
  132. Arg_t a3 = {250, 500};
  133. Arg_t a4 = {750, 250};
  134. Arg_t a5 = {100, 750};
  135. Arg_t a6 = {100, 500};
  136. Arg_t a7 = {100, 750};
  137. gMonitor = PR_NewMonitor ();
  138. fireThread ("R1", doReadThread, &a1);
  139. fireThread ("R2", doReadThread, &a2);
  140. fireThread ("R3", doReadThread, &a3);
  141. fireThread ("R4", doReadThread, &a4);
  142. fireThread ("W1", doWriteThread, &a5);
  143. fireThread ("W2", doWriteThread, &a6);
  144. fireThread ("W3", doWriteThread, &a7);
  145. fireThread ("R5", doReadThread, &a1);
  146. fireThread ("R6", doReadThread, &a2);
  147. fireThread ("R7", doReadThread, &a3);
  148. fireThread ("R8", doReadThread, &a4);
  149. fireThread ("W4", doWriteThread, &a5);
  150. fireThread ("W5", doWriteThread, &a6);
  151. fireThread ("W6", doWriteThread, &a7);
  152. while (1)
  153. {
  154. PRInt32 writeCount, readCount;
  155. PRIntervalTime fiveSecs = PR_SecondsToInterval(5);
  156. PR_Sleep (fiveSecs); // get out of the way
  157. // print some stats, not threadsafe, informative only
  158. writeCount = gCounter;
  159. readCount = gReads;
  160. printf ("\ntick %d writes (+%d), %d reads (+%d) [max %d, %d, %d]",
  161. writeCount, writeCount - lastWriteCount,
  162. readCount, readCount - lastReadCount,
  163. gMaxReads, gMaxWriteWaits, gMaxReadWaits);
  164. lastWriteCount = writeCount;
  165. lastReadCount = readCount;
  166. gMaxReads = gMaxWriteWaits = gMaxReadWaits = 0;
  167. }
  168. return 0;
  169. }
  170. static void padStack (int argc, char** argv)
  171. {
  172. char pad[512]; /* Work around bug in nspr on windoze */
  173. pseudoMain (argc, argv, pad);
  174. }
  175. int main(int argc, char **argv)
  176. {
  177. PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
  178. PR_STDIO_INIT();
  179. padStack (argc, argv);
  180. }
  181. /* bug1test.c */