]> git.saurik.com Git - apple/libpthread.git/blame_incremental - tests/cond_hang3.c
libpthread-218.1.3.tar.gz
[apple/libpthread.git] / tests / cond_hang3.c
... / ...
CommitLineData
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
14typedef long pthread_lock_t;
15
16typedef 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
25typedef 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
52static int initConditionLockWithCondition(ConditionLock *, int);
53static int lockConditionLock(ConditionLock *, int);
54static int lockConditionLockWhenCondition(ConditionLock *, int, int);
55static int unlockConditionLockWithCondition(ConditionLock *, int, int);
56static void * testThread(void *);
57
58extern int __is_threaded;
59extern int _spin_lock_try(pthread_lock_t * lockp);
60extern void _spin_unlock(pthread_lock_t * lockp);
61extern kern_return_t syscall_thread_switch(thread_t, int, int);
62
63static ConditionLock * lock;
64static volatile int count = 0;
65#if defined(LOG)
66static volatile int logcount = 0;
67static log_t * tracelog;
68static const size_t logsize = 4 * 1024 * 1024;
69pthread_lock_t loglock;
70extern int getTBR(void);
71
72static __inline__ unsigned long long
73ReadTBR()
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
102static void
103log(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
117int
118main(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
147static void *
148testThread(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
166static int
167initConditionLockWithCondition(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
187static int
188lockConditionLock(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
218static int
219lockConditionLockWhenCondition(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
252static int
253unlockConditionLockWithCondition(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
283static int
284my_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
304static int
305my_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
337static int
338my_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 */
357static int
358my_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 */
377static int
378my_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
404static int
405my_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