6 #include <mach/thread_switch.h>
8 #include <mach/mach_time.h>
10 #include <mach/sync_policy.h>
14 typedef long pthread_lock_t
;
16 typedef struct _ConditionLock
{
17 pthread_mutex_t _mutex
;
18 pthread_cond_t _condition
;
21 volatile int _isLocked
;
31 #define LOCK_INIT(l) ((l) = 0)
33 if (__is_threaded) { \
34 while (!_spin_lock_try((pthread_lock_t *)&v)) { \
35 syscall_thread_switch(THREAD_NULL, SWITCH_OPTION_WAIT, 1); \
40 _spin_unlock((pthread_lock_t *)&v)
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)
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 *);
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);
63 static ConditionLock
* lock
;
64 static volatile int count
= 0;
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);
72 static __inline__
unsigned long long
76 unsigned long long time64
;
77 unsigned long word
[2];
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. */
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
);
97 now
.time64
= mach_absolute_time();
103 log(int self
, const char * op
, ConditionLock
* cl
)
106 if (logcount
>= logsize
)
108 tracelog
[logcount
].thread
= self
;
109 tracelog
[logcount
].op
= op
;
110 tracelog
[logcount
++].tbr
= ReadTBR();
118 main(int argc
, char * argv
[])
121 long iterations
= 100000L;
123 lock
= (ConditionLock
*)calloc(sizeof(ConditionLock
), 1);
124 if (initConditionLockWithCondition(lock
, 0))
127 tracelog
= (log_t
*)calloc(logsize
, sizeof(log_t
));
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);
136 while (iterations
-- > 0) {
137 if (lockConditionLock(lock
, 0))
140 if (unlockConditionLockWithCondition(lock
, 1, 0))
143 printf("completed numerous iterations without hanging. Exiting with return 0\n");
148 testThread(void * arg
)
152 if (lockConditionLockWhenCondition(lock
, 1, self
))
156 if (unlockConditionLockWithCondition(lock
, 0, self
))
159 if (unlockConditionLockWithCondition(lock
, 1, self
))
167 initConditionLockWithCondition(ConditionLock
* cl
, int condition
)
171 if ((rc
= my_pthread_mutex_init(&cl
->_mutex
))) {
172 fprintf(stderr
, "pthread_mutex_init returned %d, %s\n", rc
, strerror(rc
));
176 if ((rc
= my_pthread_cond_init(&cl
->_condition
))) {
177 fprintf(stderr
, "pthread_cond_init returned %d, %s\n", rc
, strerror(rc
));
182 cl
->_state
= condition
;
188 lockConditionLock(ConditionLock
* cl
, int self
)
192 if ((rc
= my_pthread_mutex_lock(&cl
->_mutex
, self
))) {
193 fprintf(stderr
, "pthread_mutex_lock() returned %d, %s\n", rc
, strerror(rc
));
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
));
205 log(self
, "lock wakeup with lock held", cl
);
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
));
219 lockConditionLockWhenCondition(ConditionLock
* cl
, int condition
, int self
)
223 if ((rc
= my_pthread_mutex_lock(&cl
->_mutex
, self
))) {
224 fprintf(stderr
, "pthread_mutex_lock() returned %d, %s\n", rc
, strerror(rc
));
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
));
236 log(self
, "condition lock wakeup with lock held", cl
);
238 if (cl
->_state
!= condition
) {
239 log(self
, "condition lock wakeup with wrong condition", cl
);
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
));
253 unlockConditionLockWithCondition(ConditionLock
* cl
, int condition
, int self
)
257 if ((rc
= my_pthread_mutex_lock(&cl
->_mutex
, self
))) {
258 fprintf(stderr
, "pthread_mutex_lock() returned %d, %s\n", rc
, strerror(rc
));
261 if (cl
->_owner
!= self
) {
262 fprintf(stderr
, "%d: trying to unlock a lock owned by %d\n", self
, cl
->_owner
);
265 log(self
, condition
? "Unlocking with condition set" : "Unlocking with condition cleared", cl
);
267 cl
->_last_owner
= cl
->_owner
;
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
));
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
));
284 my_pthread_mutex_init(my_pthread_mutex_t
*mutex
)
286 kern_return_t kern_res
;
287 LOCK_INIT(mutex
->lock
);
288 mutex
->owner
= (pthread_t
)NULL
;
290 mutex
->cond_lock
= 0;
291 kern_res
= semaphore_create(mach_task_self(),
295 if (kern_res
!= KERN_SUCCESS
)
305 my_pthread_mutex_lock(my_pthread_mutex_t
*mutex
, int self
)
307 kern_return_t kern_res
;
311 if (mutex
->waiters
|| mutex
->owner
!= (pthread_t
)NULL
)
313 while (mutex
->owner
!= (pthread_t
)NULL
)
317 log(self
, "going in to sem_wait", 0);
319 kern_res
= semaphore_wait(mutex
->sem
);
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;
332 mutex
->owner
= (pthread_t
)0x12141968;
338 my_pthread_mutex_unlock(my_pthread_mutex_t
*mutex
)
340 kern_return_t kern_res
;
344 mutex
->owner
= (pthread_t
)NULL
;
345 waiters
= mutex
->waiters
;
349 kern_res
= semaphore_signal(mutex
->sem
);
355 * Initialize a condition variable. Note: 'attr' is ignored.
358 my_pthread_cond_init(my_pthread_cond_t
*cond
)
360 kern_return_t kern_res
;
361 LOCK_INIT(cond
->lock
);
363 kern_res
= semaphore_create(mach_task_self(),
367 if (kern_res
!= KERN_SUCCESS
)
375 * Signal a condition variable, waking up all threads waiting for it.
378 my_pthread_cond_broadcast(my_pthread_cond_t
*cond
)
380 kern_return_t kern_res
;
384 waiters
= cond
->waiters
;
385 if (cond
->waiters
== 0)
386 { /* Avoid kernel call since there are no waiters... */
392 kern_res
= semaphore_signal(cond
->sem
);
394 kern_res
= semaphore_signal_all(cond
->sem
);
395 if (kern_res
== KERN_SUCCESS
)
405 my_pthread_cond_wait(my_pthread_cond_t
*cond
, my_pthread_mutex_t
*mutex
, int self
)
408 kern_return_t kern_res
;
414 mutex
->cond_lock
= 1;
415 log(self
, "going in to sem_wait_signal", 0);
417 kern_res
= semaphore_wait_signal(cond
->sem
, mutex
->sem
);
420 log(self
, "woke up from sem_wait_signal", 0);
422 if ((res
= my_pthread_mutex_lock(mutex
, self
)) != ESUCCESS
)
426 if (kern_res
== KERN_SUCCESS
)