1 #include "test.h"
2 #include <sys/timeb.h>
3
4 /*
5 * Create NUMTHREADS threads in addition to the Main thread.
6 */
7 enum {
8 NUMTHREADS = 5
9 };
10
11 typedef struct bag_t_ bag_t;
12 struct bag_t_ {
13 int threadnum;
14 int started;
15 /* Add more per-thread state variables here */
16 };
17
18 static bag_t threadbag[NUMTHREADS + 1];
19
20 typedef struct cvthing_t_ cvthing_t;
21
22 struct cvthing_t_ {
23 pthread_cond_t notbusy;
24 pthread_mutex_t lock;
25 int shared;
26 };
27
28 static cvthing_t cvthing = {
29 PTHREAD_COND_INITIALIZER,
30 PTHREAD_MUTEX_INITIALIZER,
31 0
32 };
33
34 static pthread_mutex_t start_flag = PTHREAD_MUTEX_INITIALIZER;
35
36 static struct timespec abstime = { 0, 0 };
37
38 static int awoken;
39
40 static void *
mythread(void * arg)41 mythread(void * arg)
42 {
43 bag_t * bag = (bag_t *) arg;
44
45 assert(bag == &threadbag[bag->threadnum]);
46 assert(bag->started == 0);
47 bag->started = 1;
48
49 /* Wait for the start gun */
50 assert(pthread_mutex_lock(&start_flag) == 0);
51 assert(pthread_mutex_unlock(&start_flag) == 0);
52
53 assert(pthread_mutex_lock(&cvthing.lock) == 0);
54
55 #ifdef _MSC_VER
56 #pragma inline_depth(0)
57 #endif
58 pthread_cleanup_push(pthread_mutex_unlock, (void *) &cvthing.lock);
59
60 while (! (cvthing.shared > 0))
61 assert(pthread_cond_timedwait(&cvthing.notbusy, &cvthing.lock, &abstime) == 0);
62
63 pthread_cleanup_pop(0);
64 #ifdef _MSC_VER
65 #pragma inline_depth()
66 #endif
67
68 assert(cvthing.shared > 0);
69
70 awoken++;
71
72 assert(pthread_mutex_unlock(&cvthing.lock) == 0);
73
74 return (void *) 0;
75 }
76
77 int
main()78 main()
79 {
80 int failed = 0;
81 int i;
82 int first, last;
83 pthread_t t[NUMTHREADS + 1];
84
85 struct _timeb currSysTime;
86 const DWORD NANOSEC_PER_MILLISEC = 1000000;
87
88 assert((t[0] = pthread_self()) != 0);
89 assert(pthread_gethandle (t[0]) != NULL);
90
91 assert(cvthing.notbusy == PTHREAD_COND_INITIALIZER);
92
93 assert(cvthing.lock == PTHREAD_MUTEX_INITIALIZER);
94
95 _ftime(&currSysTime);
96
97 abstime.tv_sec = currSysTime.time;
98 abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.millitm;
99
100 abstime.tv_sec += 10;
101
102 assert((t[0] = pthread_self()) != 0);
103 assert(pthread_gethandle (t[0]) != NULL);
104
105 awoken = 0;
106
107 for (first = 1, last = NUMTHREADS / 2;
108 first < NUMTHREADS;
109 first = last + 1, last = NUMTHREADS)
110 {
111 assert(pthread_mutex_lock(&start_flag) == 0);
112
113 for (i = first; i <= last; i++)
114 {
115 threadbag[i].started = 0;
116 threadbag[i].threadnum = i;
117 assert(pthread_create(&t[i], NULL, mythread, (void *) &threadbag[i]) == 0);
118 }
119
120 /*
121 * Code to control or munipulate child threads should probably go here.
122 */
123 cvthing.shared = 0;
124
125 assert(pthread_mutex_unlock(&start_flag) == 0);
126
127 /*
128 * Give threads time to start.
129 */
130 Sleep(100);
131
132 assert(pthread_mutex_lock(&cvthing.lock) == 0);
133 cvthing.shared++;
134 assert(pthread_mutex_unlock(&cvthing.lock) == 0);
135
136 assert(pthread_cond_broadcast(&cvthing.notbusy) == 0);
137
138 /*
139 * Give threads time to complete.
140 */
141 for (i = first; i <= last; i++)
142 {
143 assert(pthread_join(t[i], NULL) == 0);
144 }
145
146 assert(awoken == (i - 1));
147 }
148
149
150 /*
151 * Standard check that all threads started.
152 */
153 for (i = 1; i <= NUMTHREADS; i++)
154 {
155 failed = !threadbag[i].started;
156
157 if (failed)
158 {
159 fprintf(stderr, "Thread %d: started %d\n", i, threadbag[i].started);
160 }
161 }
162
163 /*
164 * Cleanup the CV.
165 */
166
167 assert(pthread_mutex_destroy(&cvthing.lock) == 0);
168
169 assert(cvthing.lock == NULL);
170
171 assert(pthread_cond_destroy(&cvthing.notbusy) == 0);
172
173 assert(cvthing.notbusy == NULL);
174
175 assert(!failed);
176
177 /*
178 * Check any results here.
179 */
180
181 assert(awoken == NUMTHREADS);
182
183 /*
184 * Success.
185 */
186 return 0;
187 }
188