stress1.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. /*
  2. * stress1.c
  3. *
  4. *
  5. * --------------------------------------------------------------------------
  6. *
  7. * Pthreads-win32 - POSIX Threads Library for Win32
  8. * Copyright(C) 1998 John E. Bossom
  9. * Copyright(C) 1999,2005 Pthreads-win32 contributors
  10. *
  11. * Contact Email: [email protected]
  12. *
  13. * The current list of contributors is contained
  14. * in the file CONTRIBUTORS included with the source
  15. * code distribution. The list can also be seen at the
  16. * following World Wide Web location:
  17. * http://sources.redhat.com/pthreads-win32/contributors.html
  18. *
  19. * This library is free software; you can redistribute it and/or
  20. * modify it under the terms of the GNU Lesser General Public
  21. * License as published by the Free Software Foundation; either
  22. * version 2 of the License, or (at your option) any later version.
  23. *
  24. * This library is distributed in the hope that it will be useful,
  25. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  26. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  27. * Lesser General Public License for more details.
  28. *
  29. * You should have received a copy of the GNU Lesser General Public
  30. * License along with this library in the file COPYING.LIB;
  31. * if not, write to the Free Software Foundation, Inc.,
  32. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  33. *
  34. * --------------------------------------------------------------------------
  35. *
  36. * Test Synopsis:
  37. * - Stress test condition variables, mutexes, semaphores.
  38. *
  39. * Test Method (Validation or Falsification):
  40. * - Validation
  41. *
  42. * Requirements Tested:
  43. * - Correct accounting of semaphore and condition variable waiters.
  44. *
  45. * Features Tested:
  46. * -
  47. *
  48. * Cases Tested:
  49. * -
  50. *
  51. * Description:
  52. * Attempting to expose race conditions in cond vars, semaphores etc.
  53. * - Master attempts to signal slave close to when timeout is due.
  54. * - Master and slave do battle continuously until main tells them to stop.
  55. * - Afterwards, the CV must be successfully destroyed (will return an
  56. * error if there are waiters (including any internal semaphore waiters,
  57. * which, if there are, cannot be real waiters).
  58. *
  59. * Environment:
  60. * -
  61. *
  62. * Input:
  63. * - None.
  64. *
  65. * Output:
  66. * - File name, Line number, and failed expression on failure.
  67. * - No output on success.
  68. *
  69. * Assumptions:
  70. * -
  71. *
  72. * Pass Criteria:
  73. * - CV is successfully destroyed.
  74. *
  75. * Fail Criteria:
  76. * - CV destroy fails.
  77. */
  78. #include "test.h"
  79. #include <string.h>
  80. #include <sys/timeb.h>
  81. const unsigned int ITERATIONS = 1000;
  82. static pthread_t master, slave;
  83. typedef struct {
  84. int value;
  85. pthread_cond_t cv;
  86. pthread_mutex_t mx;
  87. } mysig_t;
  88. static int allExit;
  89. static mysig_t control = {0, PTHREAD_COND_INITIALIZER, PTHREAD_MUTEX_INITIALIZER};
  90. static pthread_barrier_t startBarrier, readyBarrier, holdBarrier;
  91. static int timeoutCount = 0;
  92. static int signalsTakenCount = 0;
  93. static int signalsSent = 0;
  94. static int bias = 0;
  95. static int timeout = 10; // Must be > 0
  96. enum {
  97. CTL_STOP = -1
  98. };
  99. /*
  100. * Returns abstime 'milliseconds' from 'now'.
  101. *
  102. * Works for: -INT_MAX <= millisecs <= INT_MAX
  103. */
  104. struct timespec *
  105. millisecondsFromNow (struct timespec * time, int millisecs)
  106. {
  107. PTW32_STRUCT_TIMEB currSysTime;
  108. int64_t nanosecs, secs;
  109. const int64_t NANOSEC_PER_MILLISEC = 1000000;
  110. const int64_t NANOSEC_PER_SEC = 1000000000;
  111. /* get current system time and add millisecs */
  112. PTW32_FTIME(&currSysTime);
  113. secs = (int64_t)(currSysTime.time) + (millisecs / 1000);
  114. nanosecs = ((int64_t) (millisecs%1000 + currSysTime.millitm)) * NANOSEC_PER_MILLISEC;
  115. if (nanosecs >= NANOSEC_PER_SEC)
  116. {
  117. secs++;
  118. nanosecs -= NANOSEC_PER_SEC;
  119. }
  120. else if (nanosecs < 0)
  121. {
  122. secs--;
  123. nanosecs += NANOSEC_PER_SEC;
  124. }
  125. time->tv_nsec = (long)nanosecs;
  126. time->tv_sec = (long)secs;
  127. return time;
  128. }
  129. void *
  130. masterThread (void * arg)
  131. {
  132. int dither = (int)(size_t)arg;
  133. timeout = (int)(size_t)arg;
  134. pthread_barrier_wait(&startBarrier);
  135. do
  136. {
  137. int sleepTime;
  138. assert(pthread_mutex_lock(&control.mx) == 0);
  139. control.value = timeout;
  140. assert(pthread_mutex_unlock(&control.mx) == 0);
  141. /*
  142. * We are attempting to send the signal close to when the slave
  143. * is due to timeout. We feel around by adding some [non-random] dither.
  144. *
  145. * dither is in the range 2*timeout peak-to-peak
  146. * sleep time is the average of timeout plus dither.
  147. * e.g.
  148. * if timeout = 10 then dither = 20 and
  149. * sleep millisecs is: 5 <= ms <= 15
  150. *
  151. * The bias value attempts to apply some negative feedback to keep
  152. * the ratio of timeouts to signals taken close to 1:1.
  153. * bias changes more slowly than dither so as to average more.
  154. *
  155. * Finally, if abs(bias) exceeds timeout then timeout is incremented.
  156. */
  157. if (signalsSent % timeout == 0)
  158. {
  159. if (timeoutCount > signalsTakenCount)
  160. {
  161. bias++;
  162. }
  163. else if (timeoutCount < signalsTakenCount)
  164. {
  165. bias--;
  166. }
  167. if (bias < -timeout || bias > timeout)
  168. {
  169. timeout++;
  170. }
  171. }
  172. dither = (dither + 1 ) % (timeout * 2);
  173. sleepTime = (timeout - bias + dither) / 2;
  174. Sleep(sleepTime);
  175. assert(pthread_cond_signal(&control.cv) == 0);
  176. signalsSent++;
  177. pthread_barrier_wait(&holdBarrier);
  178. pthread_barrier_wait(&readyBarrier);
  179. }
  180. while (!allExit);
  181. return NULL;
  182. }
  183. void *
  184. slaveThread (void * arg)
  185. {
  186. struct timespec time;
  187. pthread_barrier_wait(&startBarrier);
  188. do
  189. {
  190. assert(pthread_mutex_lock(&control.mx) == 0);
  191. if (pthread_cond_timedwait(&control.cv,
  192. &control.mx,
  193. millisecondsFromNow(&time, control.value)) == ETIMEDOUT)
  194. {
  195. timeoutCount++;
  196. }
  197. else
  198. {
  199. signalsTakenCount++;
  200. }
  201. assert(pthread_mutex_unlock(&control.mx) == 0);
  202. pthread_barrier_wait(&holdBarrier);
  203. pthread_barrier_wait(&readyBarrier);
  204. }
  205. while (!allExit);
  206. return NULL;
  207. }
  208. int
  209. main ()
  210. {
  211. unsigned int i;
  212. assert(pthread_barrier_init(&startBarrier, NULL, 3) == 0);
  213. assert(pthread_barrier_init(&readyBarrier, NULL, 3) == 0);
  214. assert(pthread_barrier_init(&holdBarrier, NULL, 3) == 0);
  215. assert(pthread_create(&master, NULL, masterThread, (void *)(size_t)timeout) == 0);
  216. assert(pthread_create(&slave, NULL, slaveThread, NULL) == 0);
  217. allExit = FALSE;
  218. pthread_barrier_wait(&startBarrier);
  219. for (i = 1; !allExit; i++)
  220. {
  221. pthread_barrier_wait(&holdBarrier);
  222. if (i >= ITERATIONS)
  223. {
  224. allExit = TRUE;
  225. }
  226. pthread_barrier_wait(&readyBarrier);
  227. }
  228. assert(pthread_join(slave, NULL) == 0);
  229. assert(pthread_join(master, NULL) == 0);
  230. printf("Signals sent = %d\nWait timeouts = %d\nSignals taken = %d\nBias = %d\nTimeout = %d\n",
  231. signalsSent,
  232. timeoutCount,
  233. signalsTakenCount,
  234. (int) bias,
  235. timeout);
  236. /* Cleanup */
  237. assert(pthread_barrier_destroy(&holdBarrier) == 0);
  238. assert(pthread_barrier_destroy(&readyBarrier) == 0);
  239. assert(pthread_barrier_destroy(&startBarrier) == 0);
  240. assert(pthread_cond_destroy(&control.cv) == 0);
  241. assert(pthread_mutex_destroy(&control.mx) == 0);
  242. /* Success. */
  243. return 0;
  244. }