]> git.saurik.com Git - apple/libpthread.git/blob - tests/cond_hang3.c
libpthread-301.1.6.tar.gz
[apple/libpthread.git] / tests / cond_hang3.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <pthread.h>
4 #include <string.h>
5 #include <errno.h>
6 #include <mach/thread_switch.h>
7 #include <mach/mach.h>
8 #include <mach/mach_time.h>
9 #include <mach/sync.h>
10 #include <mach/sync_policy.h>
11
12 #define LOG
13
14 typedef long pthread_lock_t;
15
16 typedef struct _ConditionLock {
17 pthread_mutex_t _mutex;
18 pthread_cond_t _condition;
19 int _owner;
20 int _last_owner;
21 volatile int _isLocked;
22 volatile int _state;
23 } ConditionLock;
24
25 typedef struct _log {
26 int thread;
27 const char * op;
28 int tbr;
29 } log_t;
30
31 #define LOCK_INIT(l) ((l) = 0)
32 #define LOCK(v) \
33 if (__is_threaded) { \
34 while (!_spin_lock_try((pthread_lock_t *)&v)) { \
35 syscall_thread_switch(THREAD_NULL, SWITCH_OPTION_WAIT, 1); \
36 } \
37 }
38 #define UNLOCK(v) \
39 if (__is_threaded) \
40 _spin_unlock((pthread_lock_t *)&v)
41 #ifndef ESUCCESS
42 #define ESUCCESS 0
43 #endif
44
45 #define my_pthread_mutex_init(m) pthread_mutex_init((m), NULL)
46 #define my_pthread_mutex_lock(m, ptself) pthread_mutex_lock(m)
47 #define my_pthread_mutex_unlock(m) pthread_mutex_unlock(m)
48 #define my_pthread_cond_init(c) pthread_cond_init((c), NULL)
49 #define my_pthread_cond_wait(c, m, ptself) pthread_cond_wait((c), (m))
50 #define my_pthread_cond_broadcast(c) pthread_cond_broadcast(c)
51
52 static int initConditionLockWithCondition(ConditionLock *, int);
53 static int lockConditionLock(ConditionLock *, int);
54 static int lockConditionLockWhenCondition(ConditionLock *, int, int);
55 static int unlockConditionLockWithCondition(ConditionLock *, int, int);
56 static void * testThread(void *);
57
58 extern int __is_threaded;
59 extern int _spin_lock_try(pthread_lock_t * lockp);
60 extern void _spin_unlock(pthread_lock_t * lockp);
61 extern kern_return_t syscall_thread_switch(thread_t, int, int);
62
63 static ConditionLock * lock;
64 static volatile int count = 0;
65 #if defined(LOG)
66 static volatile int logcount = 0;
67 static log_t * tracelog;
68 static const size_t logsize = 4 * 1024 * 1024;
69 pthread_lock_t loglock;
70 extern int getTBR(void);
71
72 static __inline__ unsigned long long
73 ReadTBR()
74 {
75 union {
76 unsigned long long time64;
77 unsigned long word[2];
78 } now;
79 #if defined(__i386__)
80 /* Read from Pentium and Pentium Pro 64-bit timestamp counter.
81 * The counter is set to 0 at processor reset and increments on
82 * every clock cycle. */
83 __asm__ volatile("rdtsc" : : : "eax", "edx");
84 __asm__ volatile("movl %%eax,%0" : "=m"(now.word[0]) : : "eax");
85 __asm__ volatile("movl %%edx,%0" : "=m"(now.word[1]) : : "edx");
86 #elif defined(__ppc__)
87 /* Read from PowerPC 64-bit time base register. The increment
88 * rate of the time base is implementation-dependent, but is
89 * 1/4th the bus clock cycle on 603/604 processors. */
90 unsigned long t3;
91 do {
92 __asm__ volatile("mftbu %0" : "=r"(now.word[0]));
93 __asm__ volatile("mftb %0" : "=r"(now.word[1]));
94 __asm__ volatile("mftbu %0" : "=r"(t3));
95 } while (now.word[0] != t3);
96 #else
97 now.time64 = mach_absolute_time();
98 #endif
99 return now.time64;
100 }
101
102 static void
103 log(int self, const char * op, ConditionLock * cl)
104 {
105 LOCK(loglock);
106 if (logcount >= logsize)
107 logcount = 0;
108 tracelog[logcount].thread = self;
109 tracelog[logcount].op = op;
110 tracelog[logcount++].tbr = ReadTBR();
111 UNLOCK(loglock);
112 }
113 #else
114 #define log(a, b, c)
115 #endif
116
117 int
118 main(int argc, char * argv[])
119 {
120 pthread_t thread[4];
121 long iterations = 100000L;
122
123 lock = (ConditionLock *)calloc(sizeof(ConditionLock), 1);
124 if (initConditionLockWithCondition(lock, 0))
125 abort();
126 #if defined(LOG)
127 tracelog = (log_t *)calloc(logsize, sizeof(log_t));
128 LOCK_INIT(loglock);
129 #endif
130
131 pthread_create(&thread[0], NULL, testThread, (void *)1);
132 pthread_create(&thread[1], NULL, testThread, (void *)2);
133 pthread_create(&thread[2], NULL, testThread, (void *)3);
134 pthread_create(&thread[3], NULL, testThread, (void *)4);
135
136 while (iterations-- > 0) {
137 if (lockConditionLock(lock, 0))
138 abort();
139 count++;
140 if (unlockConditionLockWithCondition(lock, 1, 0))
141 abort();
142 }
143 printf("completed numerous iterations without hanging. Exiting with return 0\n");
144 return 0;
145 }
146
147 static void *
148 testThread(void * arg)
149 {
150 int self = (int)arg;
151 while (1) {
152 if (lockConditionLockWhenCondition(lock, 1, self))
153 abort();
154 count--;
155 if (!count) {
156 if (unlockConditionLockWithCondition(lock, 0, self))
157 abort();
158 } else {
159 if (unlockConditionLockWithCondition(lock, 1, self))
160 abort();
161 }
162 }
163 return arg;
164 }
165
166 static int
167 initConditionLockWithCondition(ConditionLock * cl, int condition)
168 {
169 int rc;
170
171 if ((rc = my_pthread_mutex_init(&cl->_mutex))) {
172 fprintf(stderr, "pthread_mutex_init returned %d, %s\n", rc, strerror(rc));
173 return 1;
174 }
175
176 if ((rc = my_pthread_cond_init(&cl->_condition))) {
177 fprintf(stderr, "pthread_cond_init returned %d, %s\n", rc, strerror(rc));
178 return 1;
179 }
180
181 cl->_isLocked = 0;
182 cl->_state = condition;
183
184 return 0;
185 }
186
187 static int
188 lockConditionLock(ConditionLock * cl, int self)
189 {
190 int rc;
191
192 if ((rc = my_pthread_mutex_lock(&cl->_mutex, self))) {
193 fprintf(stderr, "pthread_mutex_lock() returned %d, %s\n", rc, strerror(rc));
194 return 1;
195 }
196 log(self, "Waiting for lock", cl);
197 while (cl->_isLocked) {
198 if ((rc = my_pthread_cond_wait(&cl->_condition, &cl->_mutex, self))) {
199 fprintf(stderr, "pthread_cond_wait() returned %d, %s\n", rc, strerror(rc));
200 if (rc != EINVAL) {
201 return 1;
202 }
203 }
204 if (cl->_isLocked) {
205 log(self, "lock wakeup with lock held", cl);
206 }
207 }
208 cl->_isLocked = 1;
209 cl->_owner = self;
210 log(self, "Got lock", cl);
211 if ((rc = my_pthread_mutex_unlock(&cl->_mutex))) {
212 fprintf(stderr, "pthread_mutex_unlock() %d, %s\n", rc, strerror(rc));
213 return 1;
214 }
215 return 0;
216 }
217
218 static int
219 lockConditionLockWhenCondition(ConditionLock * cl, int condition, int self)
220 {
221 int rc;
222
223 if ((rc = my_pthread_mutex_lock(&cl->_mutex, self))) {
224 fprintf(stderr, "pthread_mutex_lock() returned %d, %s\n", rc, strerror(rc));
225 return 1;
226 }
227 log(self, "Waiting for condition", cl);
228 while (cl->_isLocked || cl->_state != condition) {
229 if ((rc = my_pthread_cond_wait(&cl->_condition, &cl->_mutex, self))) {
230 fprintf(stderr, "pthread_cond_wait() returned %d, %s\n", rc, strerror(rc));
231 if (rc != EINVAL) {
232 return 1;
233 }
234 }
235 if (cl->_isLocked) {
236 log(self, "condition lock wakeup with lock held", cl);
237 }
238 if (cl->_state != condition) {
239 log(self, "condition lock wakeup with wrong condition", cl);
240 }
241 }
242 cl->_isLocked = 1;
243 cl->_owner = self;
244 log(self, "Got condition", cl);
245 if ((rc = my_pthread_mutex_unlock(&cl->_mutex))) {
246 fprintf(stderr, "pthread_mutex_unlock() returned %d, %s\n", rc, strerror(rc));
247 return 1;
248 }
249 return 0;
250 }
251
252 static int
253 unlockConditionLockWithCondition(ConditionLock * cl, int condition, int self)
254 {
255 int rc;
256
257 if ((rc = my_pthread_mutex_lock(&cl->_mutex, self))) {
258 fprintf(stderr, "pthread_mutex_lock() returned %d, %s\n", rc, strerror(rc));
259 return 1;
260 }
261 if (cl->_owner != self) {
262 fprintf(stderr, "%d: trying to unlock a lock owned by %d\n", self, cl->_owner);
263 abort();
264 }
265 log(self, condition ? "Unlocking with condition set" : "Unlocking with condition cleared", cl);
266 cl->_isLocked = 0;
267 cl->_last_owner = cl->_owner;
268 cl->_owner = 0;
269 cl->_state = condition;
270 if ((rc = my_pthread_cond_broadcast(&cl->_condition))) {
271 fprintf(stderr, "pthread_cond_broadcast() returned %d, %s\n", rc, strerror(rc));
272 return 1;
273 }
274 log(self, "Sent broadcast", cl);
275 if ((rc = my_pthread_mutex_unlock(&cl->_mutex))) {
276 fprintf(stderr, "pthread_mutex_unlock() returned %d, %s\n", rc, strerror(rc));
277 return 1;
278 }
279 return 0;
280 }
281
282 #if 0
283 static int
284 my_pthread_mutex_init(my_pthread_mutex_t *mutex)
285 {
286 kern_return_t kern_res;
287 LOCK_INIT(mutex->lock);
288 mutex->owner = (pthread_t)NULL;
289 mutex->waiters = 0;
290 mutex->cond_lock = 0;
291 kern_res = semaphore_create(mach_task_self(),
292 &mutex->sem,
293 SYNC_POLICY_FIFO,
294 0);
295 if (kern_res != KERN_SUCCESS)
296 {
297 return (ENOMEM);
298 } else
299 {
300 return (ESUCCESS);
301 }
302 }
303
304 static int
305 my_pthread_mutex_lock(my_pthread_mutex_t *mutex, int self)
306 {
307 kern_return_t kern_res;
308
309 LOCK(mutex->lock);
310 #if 0
311 if (mutex->waiters || mutex->owner != (pthread_t)NULL)
312 #else
313 while (mutex->owner != (pthread_t)NULL)
314 #endif
315 {
316 mutex->waiters++;
317 log(self, "going in to sem_wait", 0);
318 UNLOCK(mutex->lock);
319 kern_res = semaphore_wait(mutex->sem);
320 LOCK(mutex->lock);
321 mutex->waiters--;
322 log(self, "woke up from sem_wait", 0);
323 if (mutex->cond_lock) {
324 log(self, "clearing cond_lock", 0);
325 mutex->cond_lock = 0;
326 #if 0
327 #else
328 break;
329 #endif
330 }
331 }
332 mutex->owner = (pthread_t)0x12141968;
333 UNLOCK(mutex->lock);
334 return (ESUCCESS);
335 }
336
337 static int
338 my_pthread_mutex_unlock(my_pthread_mutex_t *mutex)
339 {
340 kern_return_t kern_res;
341 int waiters;
342
343 LOCK(mutex->lock);
344 mutex->owner = (pthread_t)NULL;
345 waiters = mutex->waiters;
346 UNLOCK(mutex->lock);
347 if (waiters)
348 {
349 kern_res = semaphore_signal(mutex->sem);
350 }
351 return (ESUCCESS);
352 }
353
354 /*
355 * Initialize a condition variable. Note: 'attr' is ignored.
356 */
357 static int
358 my_pthread_cond_init(my_pthread_cond_t *cond)
359 {
360 kern_return_t kern_res;
361 LOCK_INIT(cond->lock);
362 cond->waiters = 0;
363 kern_res = semaphore_create(mach_task_self(),
364 &cond->sem,
365 SYNC_POLICY_FIFO,
366 0);
367 if (kern_res != KERN_SUCCESS)
368 {
369 return (ENOMEM);
370 }
371 return (ESUCCESS);
372 }
373
374 /*
375 * Signal a condition variable, waking up all threads waiting for it.
376 */
377 static int
378 my_pthread_cond_broadcast(my_pthread_cond_t *cond)
379 {
380 kern_return_t kern_res;
381 int waiters;
382
383 LOCK(cond->lock);
384 waiters = cond->waiters;
385 if (cond->waiters == 0)
386 { /* Avoid kernel call since there are no waiters... */
387 UNLOCK(cond->lock);
388 return (ESUCCESS);
389 }
390 UNLOCK(cond->lock);
391 #if 0
392 kern_res = semaphore_signal(cond->sem);
393 #endif
394 kern_res = semaphore_signal_all(cond->sem);
395 if (kern_res == KERN_SUCCESS)
396 {
397 return (ESUCCESS);
398 } else
399 {
400 return (EINVAL);
401 }
402 }
403
404 static int
405 my_pthread_cond_wait(my_pthread_cond_t *cond, my_pthread_mutex_t *mutex, int self)
406 {
407 int res;
408 kern_return_t kern_res;
409
410 LOCK(cond->lock);
411 cond->waiters++;
412 UNLOCK(cond->lock);
413 LOCK(mutex->lock);
414 mutex->cond_lock = 1;
415 log(self, "going in to sem_wait_signal", 0);
416 UNLOCK(mutex->lock);
417 kern_res = semaphore_wait_signal(cond->sem, mutex->sem);
418 LOCK(cond->lock);
419 cond->waiters--;
420 log(self, "woke up from sem_wait_signal", 0);
421 UNLOCK(cond->lock);
422 if ((res = my_pthread_mutex_lock(mutex, self)) != ESUCCESS)
423 {
424 return (res);
425 }
426 if (kern_res == KERN_SUCCESS)
427 {
428 return (ESUCCESS);
429 } else
430 {
431 return (EINVAL);
432 }
433 }
434
435 #endif