• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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: rpj@callisto.canberra.edu.au
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  *      59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 
79 #include "test.h"
80 #include <string.h>
81 #include <sys/timeb.h>
82 
83 
84 const unsigned int ITERATIONS = 1000;
85 
86 static pthread_t master, slave;
87 typedef struct {
88   int value;
89   pthread_cond_t cv;
90   pthread_mutex_t mx;
91 } mysig_t;
92 
93 static int allExit;
94 static mysig_t control = {0, PTHREAD_COND_INITIALIZER, PTHREAD_MUTEX_INITIALIZER};
95 static pthread_barrier_t startBarrier, readyBarrier, holdBarrier;
96 static int timeoutCount = 0;
97 static int signalsTakenCount = 0;
98 static int signalsSent = 0;
99 static int bias = 0;
100 static int timeout = 10; // Must be > 0
101 
102 enum {
103   CTL_STOP     = -1
104 };
105 
106 /*
107  * Returns abstime 'milliseconds' from 'now'.
108  *
109  * Works for: -INT_MAX <= millisecs <= INT_MAX
110  */
111 struct timespec *
millisecondsFromNow(struct timespec * time,int millisecs)112 millisecondsFromNow (struct timespec * time, int millisecs)
113 {
114   struct _timeb currSysTime;
115   int64_t nanosecs, secs;
116   const int64_t NANOSEC_PER_MILLISEC = 1000000;
117   const int64_t NANOSEC_PER_SEC = 1000000000;
118 
119   /* get current system time and add millisecs */
120   _ftime(&currSysTime);
121 
122   secs = (int64_t)(currSysTime.time) + (millisecs / 1000);
123   nanosecs = ((int64_t) (millisecs%1000 + currSysTime.millitm)) * NANOSEC_PER_MILLISEC;
124   if (nanosecs >= NANOSEC_PER_SEC)
125     {
126       secs++;
127       nanosecs -= NANOSEC_PER_SEC;
128     }
129   else if (nanosecs < 0)
130     {
131       secs--;
132       nanosecs += NANOSEC_PER_SEC;
133     }
134 
135   time->tv_nsec = (long)nanosecs;
136   time->tv_sec = (long)secs;
137 
138   return time;
139 }
140 
141 void *
masterThread(void * arg)142 masterThread (void * arg)
143 {
144   int dither = (int) (size_t) arg;
145 
146   timeout = (int) (size_t) arg;
147 
148   pthread_barrier_wait(&startBarrier);
149 
150   do
151     {
152       int sleepTime;
153 
154       assert(pthread_mutex_lock(&control.mx) == 0);
155       control.value = timeout;
156       assert(pthread_mutex_unlock(&control.mx) == 0);
157 
158       /*
159        * We are attempting to send the signal close to when the slave
160        * is due to timeout. We feel around by adding some [non-random] dither.
161        *
162        * dither is in the range 2*timeout peak-to-peak
163        * sleep time is the average of timeout plus dither.
164        * e.g.
165        * if timeout = 10 then dither = 20 and
166        * sleep millisecs is: 5 <= ms <= 15
167        *
168        * The bias value attempts to apply some negative feedback to keep
169        * the ratio of timeouts to signals taken close to 1:1.
170        * bias changes more slowly than dither so as to average more.
171        *
172        * Finally, if abs(bias) exceeds timeout then timeout is incremented.
173        */
174       if (signalsSent % timeout == 0)
175 	{
176           if (timeoutCount > signalsTakenCount)
177 	    {
178 	      bias++;
179 	    }
180           else if (timeoutCount < signalsTakenCount)
181 	    {
182 	      bias--;
183 	    }
184 	  if (bias < -timeout || bias > timeout)
185 	    {
186 	      timeout++;
187 	    }
188 	}
189       dither = (dither + 1 ) % (timeout * 2);
190       sleepTime = (timeout - bias + dither) / 2;
191       Sleep(sleepTime);
192       assert(pthread_cond_signal(&control.cv) == 0);
193       signalsSent++;
194 
195       pthread_barrier_wait(&holdBarrier);
196       pthread_barrier_wait(&readyBarrier);
197     }
198   while (!allExit);
199 
200   return NULL;
201 }
202 
203 void *
slaveThread(void * arg)204 slaveThread (void * arg)
205 {
206   struct timespec time;
207 
208   pthread_barrier_wait(&startBarrier);
209 
210   do
211     {
212       assert(pthread_mutex_lock(&control.mx) == 0);
213       if (pthread_cond_timedwait(&control.cv,
214 				 &control.mx,
215 				 millisecondsFromNow(&time, control.value)) == ETIMEDOUT)
216 	{
217 	  timeoutCount++;
218 	}
219       else
220 	{
221 	  signalsTakenCount++;
222 	}
223       assert(pthread_mutex_unlock(&control.mx) == 0);
224 
225       pthread_barrier_wait(&holdBarrier);
226       pthread_barrier_wait(&readyBarrier);
227     }
228   while (!allExit);
229 
230   return NULL;
231 }
232 
233 int
main()234 main ()
235 {
236   unsigned int i;
237 
238   assert(pthread_barrier_init(&startBarrier, NULL, 3) == 0);
239   assert(pthread_barrier_init(&readyBarrier, NULL, 3) == 0);
240   assert(pthread_barrier_init(&holdBarrier, NULL, 3) == 0);
241 
242   assert(pthread_create(&master, NULL, masterThread, (void *) (size_t) timeout) == 0);
243   assert(pthread_create(&slave, NULL, slaveThread, NULL) == 0);
244 
245   allExit = FALSE;
246 
247   pthread_barrier_wait(&startBarrier);
248 
249   for (i = 1; !allExit; i++)
250     {
251       pthread_barrier_wait(&holdBarrier);
252       if (i >= ITERATIONS)
253 	{
254 	  allExit = TRUE;
255 	}
256       pthread_barrier_wait(&readyBarrier);
257     }
258 
259   assert(pthread_join(slave, NULL) == 0);
260   assert(pthread_join(master, NULL) == 0);
261 
262   printf("Signals sent = %d\nWait timeouts = %d\nSignals taken = %d\nBias = %d\nTimeout = %d\n",
263 	 signalsSent,
264 	 timeoutCount,
265 	 signalsTakenCount,
266 	 (int) bias,
267 	 timeout);
268 
269   /* Cleanup */
270   assert(pthread_barrier_destroy(&holdBarrier) == 0);
271   assert(pthread_barrier_destroy(&readyBarrier) == 0);
272   assert(pthread_barrier_destroy(&startBarrier) == 0);
273   assert(pthread_cond_destroy(&control.cv) == 0);
274   assert(pthread_mutex_destroy(&control.mx) == 0);
275 
276   /* Success. */
277   return 0;
278 }
279