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