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 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 while (! (cvthing.shared > 0))
56 assert(pthread_cond_timedwait(&cvthing.notbusy, &cvthing.lock, &abstime) == 0);
57
58 assert(cvthing.shared > 0);
59
60 awoken++;
61
62 assert(pthread_mutex_unlock(&cvthing.lock) == 0);
63
64 return (void *) 0;
65 }
66
67 int
main()68 main()
69 {
70 int failed = 0;
71 int i;
72 pthread_t t[NUMTHREADS + 1];
73
74 struct _timeb currSysTime;
75 const DWORD NANOSEC_PER_MILLISEC = 1000000;
76
77 cvthing.shared = 0;
78
79 assert((t[0] = pthread_self()) != 0);
80 assert(pthread_gethandle (t[0]) != NULL);
81
82 assert(cvthing.notbusy == PTHREAD_COND_INITIALIZER);
83
84 assert(cvthing.lock == PTHREAD_MUTEX_INITIALIZER);
85
86 assert(pthread_mutex_lock(&start_flag) == 0);
87
88 _ftime(&currSysTime);
89
90 abstime.tv_sec = currSysTime.time;
91 abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.millitm;
92
93 abstime.tv_sec += 5;
94
95 assert((t[0] = pthread_self()) != 0);
96 assert(pthread_gethandle (t[0]) != NULL);
97
98 awoken = 0;
99
100 for (i = 1; i <= NUMTHREADS; i++)
101 {
102 threadbag[i].started = 0;
103 threadbag[i].threadnum = i;
104 assert(pthread_create(&t[i], NULL, mythread, (void *) &threadbag[i]) == 0);
105 }
106
107 /*
108 * Code to control or munipulate child threads should probably go here.
109 */
110
111 assert(pthread_mutex_unlock(&start_flag) == 0);
112
113 /*
114 * Give threads time to start.
115 */
116 Sleep(1000);
117
118 assert(pthread_mutex_lock(&cvthing.lock) == 0);
119 cvthing.shared++;
120 assert(pthread_mutex_unlock(&cvthing.lock) == 0);
121
122 assert(pthread_cond_broadcast(&cvthing.notbusy) == 0);
123
124 /*
125 * Give threads time to complete.
126 */
127 for (i = 1; i <= NUMTHREADS; i++)
128 {
129 assert(pthread_join(t[i], NULL) == 0);
130 }
131
132 /*
133 * Cleanup the CV.
134 */
135
136 assert(pthread_mutex_destroy(&cvthing.lock) == 0);
137
138 assert(cvthing.lock == NULL);
139
140 assert(pthread_cond_destroy(&cvthing.notbusy) == 0);
141
142 assert(cvthing.notbusy == NULL);
143
144 /*
145 * Standard check that all threads started.
146 */
147 for (i = 1; i <= NUMTHREADS; i++)
148 {
149 failed = !threadbag[i].started;
150
151 if (failed)
152 {
153 fprintf(stderr, "Thread %d: started %d\n", i, threadbag[i].started);
154 }
155 }
156
157 assert(!failed);
158
159 /*
160 * Check any results here.
161 */
162
163 assert(awoken == NUMTHREADS);
164
165 /*
166 * Success.
167 */
168 return 0;
169 }
170
171
172