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
_pthread_mutex_unlock_cleanup(pthread_mutex_t arg)40 static void _pthread_mutex_unlock_cleanup (pthread_mutex_t arg)
41 {
42 pthread_mutex_t *m = (pthread_mutex_t *)arg;
43
44 pthread_mutex_unlock (m);
45 }
46
47 void *
mythread(void * arg)48 mythread(void * arg)
49 {
50 bag_t * bag = (bag_t *) arg;
51
52 assert(bag == &threadbag[bag->threadnum]);
53 assert(bag->started == 0);
54 bag->started = 1;
55
56 /* Wait for the start gun */
57 assert(pthread_mutex_lock(&start_flag) == 0);
58 assert(pthread_mutex_unlock(&start_flag) == 0);
59
60 assert(pthread_mutex_lock(&cvthing.lock) == 0);
61
62 #ifdef _MSC_VER
63 #pragma inline_depth(0)
64 #endif
65 pthread_cleanup_push(_pthread_mutex_unlock_cleanup, (void *) &cvthing.lock);
66
67 while (! (cvthing.shared > 0)) {
68 int r = pthread_cond_timedwait(&cvthing.notbusy, &cvthing.lock, &abstime);
69 assert(r == 0);
70 }
71
72 pthread_cleanup_pop(0);
73 #ifdef _MSC_VER
74 #pragma inline_depth()
75 #endif
76
77 assert(cvthing.shared > 0);
78
79 awoken++;
80
81 assert(pthread_mutex_unlock(&cvthing.lock) == 0);
82
83 return (void *) 0;
84 }
85
86 int
main()87 main()
88 {
89 int failed = 0;
90 int i;
91 pthread_t t[NUMTHREADS + 1];
92
93 struct _timeb currSysTime;
94 const DWORD NANOSEC_PER_MILLISEC = 1000000;
95
96 cvthing.shared = 0;
97
98 assert((t[0] = pthread_self()) != 0);
99 assert(pthread_gethandle (t[0]) != NULL);
100
101 assert(cvthing.notbusy == PTHREAD_COND_INITIALIZER);
102
103 assert(cvthing.lock == PTHREAD_MUTEX_INITIALIZER);
104
105 assert(pthread_mutex_lock(&start_flag) == 0);
106
107 _ftime(&currSysTime);
108
109 abstime.tv_sec = currSysTime.time;
110 abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.millitm;
111
112 abstime.tv_sec += 10;
113
114 assert((t[0] = pthread_self()) != 0);
115 assert(pthread_gethandle (t[0]) != NULL);
116
117 awoken = 0;
118
119 for (i = 1; i <= NUMTHREADS; i++)
120 {
121 threadbag[i].started = 0;
122 threadbag[i].threadnum = i;
123 assert(pthread_create(&t[i], NULL, mythread, (void *) &threadbag[i]) == 0);
124 }
125
126 /*
127 * Code to control or munipulate child threads should probably go here.
128 */
129
130 assert(pthread_mutex_unlock(&start_flag) == 0);
131
132 /*
133 * Give threads time to start.
134 */
135 Sleep(1000);
136
137 /*
138 * Cancel one of the threads.
139 */
140 assert(pthread_cancel(t[1]) == 0);
141 assert(pthread_join(t[1], NULL) == 0);
142
143 assert(pthread_mutex_lock(&cvthing.lock) == 0);
144 cvthing.shared++;
145 assert(pthread_mutex_unlock(&cvthing.lock) == 0);
146
147 /*
148 * Signal all remaining waiting threads.
149 */
150 assert(pthread_cond_broadcast(&cvthing.notbusy) == 0);
151
152 /*
153 * Wait for all threads to complete.
154 */
155 for (i = 2; i <= NUMTHREADS; i++)
156 assert(pthread_join(t[i], NULL) == 0);
157
158 /*
159 * Cleanup the CV.
160 */
161
162 assert(pthread_mutex_destroy(&cvthing.lock) == 0);
163
164 assert(cvthing.lock == NULL);
165
166 assert(pthread_cond_destroy(&cvthing.notbusy) == 0);
167
168 assert(cvthing.notbusy == NULL);
169
170 /*
171 * Standard check that all threads started.
172 */
173 for (i = 1; i <= NUMTHREADS; i++)
174 {
175 failed = !threadbag[i].started;
176
177 if (failed)
178 {
179 fprintf(stderr, "Thread %d: started %d\n", i, threadbag[i].started);
180 }
181 }
182
183 assert(!failed);
184
185 /*
186 * Check any results here.
187 */
188
189 assert(awoken == (NUMTHREADS - 1));
190
191 /*
192 * Success.
193 */
194 return 0;
195 }
196