3a4cc0f054993b926fee1c25595a549de86cbd7c
[cacao.git] / src / threads / native / threads.c
1 #include "global.h"
2
3 #if defined(NATIVE_THREADS)
4
5 #include <stdlib.h>
6 #include <string.h>
7 #include <assert.h>
8 #include <sys/types.h>
9 #include <unistd.h>
10 #include <signal.h>
11 #include <sys/time.h>
12 #include <time.h>
13 #include <errno.h>
14
15 #include "config.h"
16 #include "thread.h"
17 #include "codegen.h"
18 #include "locks.h"
19 #include "tables.h"
20 #include "native.h"
21 #include "loader.h"
22 #include "builtin.h"
23 #include "asmpart.h"
24 #include "toolbox/logging.h"
25 #include "toolbox/memory.h"
26 #include "toolbox/avl.h"
27 #include "mm/boehm.h"
28
29 #include "nat/java_lang_Object.h"
30 #include "nat/java_lang_Throwable.h"
31 #include "nat/java_lang_Thread.h"
32 #include "nat/java_lang_ThreadGroup.h"
33
34 #include <pthread.h>
35 #include <semaphore.h>
36
37 #if defined(__LINUX__)
38 #define GC_LINUX_THREADS
39 #include "../mm/boehm-gc/include/gc.h"
40 #endif
41
42 #ifdef MUTEXSIM
43
44 typedef struct {
45         pthread_mutex_t mutex;
46         pthread_t owner;
47         int count;
48 } pthread_mutex_rec_t;
49
50 static void pthread_mutex_init_rec(pthread_mutex_rec_t *m)
51 {
52         pthread_mutex_init(&m->mutex, NULL);
53         m->count = 0;
54 }
55
56 static void pthread_mutex_destroy_rec(pthread_mutex_rec_t *m)
57 {
58         pthread_mutex_destroy(&m->mutex);
59 }
60
61 static void pthread_mutex_lock_rec(pthread_mutex_rec_t *m)
62 {
63         for (;;)
64                 if (!m->count)
65                 {
66                         pthread_mutex_lock(&m->mutex);
67                         m->owner = pthread_self();
68                         m->count++;
69                         break;
70                 } else {
71                         if (m->owner != pthread_self())
72                                 pthread_mutex_lock(&m->mutex);
73                         else
74                         {
75                                 m->count++;
76                                 break;
77                         }
78                 }
79 }
80
81 static void pthread_mutex_unlock_rec(pthread_mutex_rec_t *m)
82 {
83         if (!--m->count)
84                 pthread_mutex_unlock(&m->mutex);
85 }
86
87 #else /* MUTEXSIM */
88
89 #define pthread_mutex_lock_rec pthread_mutex_lock
90 #define pthread_mutex_unlock_rec pthread_mutex_unlock
91 #define pthread_mutex_rec_t pthread_mutex_t
92
93 #endif /* MUTEXSIM */
94
95 #include "machine-instr.h"
96
97 static struct avl_table *criticaltree;
98 static threadobject *mainthreadobj;
99
100 #ifndef HAVE___THREAD
101 pthread_key_t tkey_threadinfo;
102 #else
103 __thread threadobject *threadobj;
104 #endif
105
106 static pthread_mutex_rec_t compiler_mutex;
107 static pthread_mutex_rec_t tablelock;
108
109 void compiler_lock()
110 {
111         pthread_mutex_lock_rec(&compiler_mutex);
112 }
113
114 void compiler_unlock()
115 {
116         pthread_mutex_unlock_rec(&compiler_mutex);
117 }
118
119 void tables_lock()
120 {
121     pthread_mutex_lock_rec(&tablelock);
122 }
123
124 void tables_unlock()
125 {
126     pthread_mutex_unlock_rec(&tablelock);
127 }
128
129 static int criticalcompare(const void *pa, const void *pb, void *param)
130 {
131         const threadcritnode *na = pa;
132         const threadcritnode *nb = pb;
133
134         if (na->mcodebegin < nb->mcodebegin)
135                 return -1;
136         if (na->mcodebegin > nb->mcodebegin)
137                 return 1;
138         return 0;
139 }
140
141 static const threadcritnode *findcritical(u1 *mcodeptr)
142 {
143     struct avl_node *n = criticaltree->avl_root;
144     const threadcritnode *m = NULL;
145     if (!n)
146         return NULL;
147     for (;;)
148     {
149         const threadcritnode *d = n->avl_data;
150         if (mcodeptr == d->mcodebegin)
151             return d;
152         if (mcodeptr < d->mcodebegin) {
153             if (n->avl_link[0])
154                 n = n->avl_link[0];
155             else
156                 return m;
157         } else {
158             if (n->avl_link[1]) {
159                 m = n->avl_data;
160                 n = n->avl_link[1];
161             } else
162                 return n->avl_data;
163         }
164     }
165 }
166
167 void thread_registercritical(threadcritnode *n)
168 {
169         avl_insert(criticaltree, n);
170 }
171
172 u1 *thread_checkcritical(u1 *mcodeptr)
173 {
174         const threadcritnode *n = findcritical(mcodeptr);
175         return (n && mcodeptr < n->mcodeend && mcodeptr > n->mcodebegin) ? n->mcoderestart : NULL;
176 }
177
178 static void thread_addstaticcritical()
179 {
180         threadcritnode *n = &asm_criticalsections;
181
182         while (n->mcodebegin)
183                 thread_registercritical(n++);
184 }
185
186 static pthread_mutex_t threadlistlock;
187
188 static pthread_mutex_t stopworldlock;
189 volatile int stopworldwhere;
190
191 static sem_t suspend_ack;
192
193 /*
194  * where - 1 from within GC
195            2 class numbering
196  */
197 void lock_stopworld(int where)
198 {
199         pthread_mutex_lock(&stopworldlock);
200         stopworldwhere = where;
201 }
202
203 void unlock_stopworld()
204 {
205         stopworldwhere = 0;
206         pthread_mutex_unlock(&stopworldlock);
207 }
208
209 #if !defined(__DARWIN__)
210 /* Caller must hold threadlistlock */
211 static int cast_sendsignals(int sig, int count)
212 {
213         /* Count threads */
214         threadobject *tobj = mainthreadobj;
215         nativethread *infoself = THREADINFO;
216
217         if (count == 0)
218                 do {
219                         count++;
220                         tobj = tobj->info.next;
221                 } while (tobj != mainthreadobj);
222
223         do {
224                 nativethread *info = &tobj->info;
225                 if (info != infoself)
226                         pthread_kill(info->tid, sig);
227                 tobj = tobj->info.next;
228         } while (tobj != mainthreadobj);
229
230         return count-1;
231 }
232 #endif
233
234 void cast_stopworld()
235 {
236         int count, i;
237         lock_stopworld(2);
238         pthread_mutex_lock(&threadlistlock);
239 #if defined(__DARWIN__)
240         /* XXX stop threads using mach functions */
241 #else
242         count = cast_sendsignals(GC_signum1(), 0);
243         for (i=0; i<count; i++)
244                 sem_wait(&suspend_ack);
245 #endif
246         pthread_mutex_unlock(&threadlistlock);
247 }
248
249 void cast_startworld()
250 {
251         pthread_mutex_lock(&threadlistlock);
252 #if defined(__DARWIN__)
253         /* XXX resume threads using mach functions */
254 #else
255         cast_sendsignals(GC_signum2(), -1);
256 #endif
257         pthread_mutex_unlock(&threadlistlock);
258         unlock_stopworld();
259 }
260
261 #if !defined(__DARWIN__)
262 static void sigsuspend_handler(ucontext_t *ctx)
263 {
264         int sig;
265         sigset_t sigs;
266         
267         thread_restartcriticalsection(ctx);
268
269         sem_post(&suspend_ack);
270
271         sig = GC_signum2();
272         sigfillset(&sigs);
273         sigdelset(&sigs, sig);
274         sigsuspend(&sigs);
275 }
276
277 int cacao_suspendhandler(ucontext_t *ctx)
278 {
279         if (stopworldwhere != 2)
280                 return 0;
281
282         sigsuspend_handler(ctx);
283         return 1;
284 }
285 #endif
286
287 static void setthreadobject(threadobject *thread)
288 {
289 #if !defined(HAVE___THREAD)
290         pthread_setspecific(tkey_threadinfo, thread);
291 #else
292         threadobj = thread;
293 #endif
294 }
295
296 /*
297  * Initialize threads.
298  */
299 void
300 initThreadsEarly()
301 {
302 #ifndef MUTEXSIM
303         pthread_mutexattr_t mutexattr;
304         pthread_mutexattr_init(&mutexattr);
305         pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_RECURSIVE);
306         pthread_mutex_init(&compiler_mutex, &mutexattr);
307         pthread_mutex_init(&tablelock, &mutexattr);
308         pthread_mutexattr_destroy(&mutexattr);
309 #else
310         pthread_mutex_init_rec(&compiler_mutex);
311         pthread_mutex_init_rec(&tablelock);
312 #endif
313
314         pthread_mutex_init(&threadlistlock, NULL);
315         pthread_mutex_init(&stopworldlock, NULL);
316
317         /* Allocate something so the garbage collector's signal handlers are  */
318         /* installed. */
319         heap_allocate(1, false, NULL);
320
321         mainthreadobj = NEW(threadobject);
322         memset(mainthreadobj, 0, sizeof(threadobject));
323 #if !defined(HAVE___THREAD)
324         pthread_key_create(&tkey_threadinfo, NULL);
325 #endif
326         setthreadobject(mainthreadobj);
327
328     criticaltree = avl_create(criticalcompare, NULL, NULL);
329         thread_addstaticcritical();
330         sem_init(&suspend_ack, 0, 0);
331 }
332
333 static pthread_attr_t threadattr;
334 static void freeLockRecordPools(lockRecordPool *);
335
336 void
337 initThreads(u1 *stackbottom)
338 {
339         classinfo *threadclass;
340         classinfo *threadgroupclass;
341         java_lang_Thread *mainthread;
342         threadobject *tempthread = mainthreadobj;
343
344         threadclass = class_new(utf_new_char("java/lang/Thread"));
345         class_load(threadclass);
346         class_link(threadclass);
347
348         assert(threadclass);
349         freeLockRecordPools(mainthreadobj->ee.lrpool);
350         threadclass->instancesize = sizeof(threadobject);
351
352         mainthreadobj = (threadobject *) builtin_new(threadclass);
353         assert(mainthreadobj);
354
355         FREE(tempthread, threadobject);
356         initThread(&mainthreadobj->o);
357
358 #if !defined(HAVE___THREAD)
359         pthread_setspecific(tkey_threadinfo, mainthreadobj);
360 #else
361         threadobj = mainthreadobj;
362 #endif
363
364         mainthread = &mainthreadobj->o;
365         initLocks();
366         mainthreadobj->info.next = mainthreadobj;
367         mainthreadobj->info.prev = mainthreadobj;
368
369         mainthread->name=javastring_new(utf_new_char("main"));
370
371         /* Allocate and init ThreadGroup */
372         threadgroupclass = class_new(utf_new_char("java/lang/ThreadGroup"));
373         class_load(threadgroupclass);
374         class_link(threadgroupclass);
375
376         mainthread->group =
377                 (java_lang_ThreadGroup *) native_new_and_init(threadgroupclass);
378         assert(mainthread->group != 0);
379
380         pthread_attr_init(&threadattr);
381         pthread_attr_setdetachstate(&threadattr, PTHREAD_CREATE_DETACHED);
382 }
383
384 void initThread(java_lang_Thread *t)
385 {
386         nativethread *info = &((threadobject*) t)->info;
387         pthread_mutex_init(&info->joinMutex, NULL);
388         pthread_cond_init(&info->joinCond, NULL);
389 }
390
391 static void initThreadLocks(threadobject *);
392
393 typedef struct {
394         threadobject *thread;
395         sem_t *psem;
396 } startupinfo;
397
398 static void *threadstartup(void *t)
399 {
400         startupinfo *startup = t;
401         threadobject *thread = startup->thread;
402         sem_t *psem = startup->psem;
403         nativethread *info = &thread->info;
404         threadobject *tnext;
405         methodinfo *method;
406
407         t = NULL;
408 #if defined(__DARWIN__)
409         info->mach_thread = mach_thread_self();
410 #endif
411         setthreadobject(thread);
412
413         pthread_mutex_lock(&threadlistlock);
414         info->prev = mainthreadobj;
415         info->next = tnext = mainthreadobj->info.next;
416         mainthreadobj->info.next = thread;
417         tnext->info.prev = thread;
418         pthread_mutex_unlock(&threadlistlock);
419
420         initThreadLocks(thread);
421
422         startup = NULL;
423         sem_post(psem);
424
425         /* Find the run()V method and call it */
426         method = class_findmethod(thread->o.header.vftbl->class,
427                                                           utf_new_char("run"), utf_new_char("()V"));
428         if (!method)
429                 panic("Cannot find method \'void run ()\'");
430
431         asm_calljavafunction(method, thread, NULL, NULL, NULL);
432
433     if (info->_exceptionptr) {
434         utf_display_classname((info->_exceptionptr)->vftbl->class->name);
435         printf("\n");
436     }
437
438         freeLockRecordPools(thread->ee.lrpool);
439
440         pthread_mutex_lock(&threadlistlock);
441         info->next->info.prev = info->prev;
442         info->prev->info.next = info->next;
443         pthread_mutex_unlock(&threadlistlock);
444
445         pthread_mutex_lock(&info->joinMutex);
446         info->tid = 0;
447         pthread_mutex_unlock(&info->joinMutex);
448         pthread_cond_broadcast(&info->joinCond);
449
450         return NULL;
451 }
452
453 void startThread(threadobject *t)
454 {
455         nativethread *info = &t->info;
456         sem_t sem;
457         startupinfo startup;
458
459         startup.thread = t;
460         startup.psem = &sem;
461
462         sem_init(&sem, 0, 0);
463         
464         if (pthread_create(&info->tid, &threadattr, threadstartup, &startup))
465                 panic("pthread_create failed");
466
467         /* Wait here until thread has entered itself into the thread list */
468         sem_wait(&sem);
469         sem_destroy(&sem);
470 }
471
472 void joinAllThreads()
473 {
474         pthread_mutex_lock(&threadlistlock);
475         while (mainthreadobj->info.prev != mainthreadobj) {
476                 nativethread *info = &mainthreadobj->info.prev->info;
477                 pthread_mutex_lock(&info->joinMutex);
478                 pthread_mutex_unlock(&threadlistlock);
479                 if (info->tid)
480                         pthread_cond_wait(&info->joinCond, &info->joinMutex);
481                 pthread_mutex_unlock(&info->joinMutex);
482                 pthread_mutex_lock(&threadlistlock);
483         }
484         pthread_mutex_unlock(&threadlistlock);
485 }
486
487 bool aliveThread(java_lang_Thread *t)
488 {
489         return ((threadobject*) t)->info.tid != 0;
490 }
491
492 void sleepThread(s8 millis)
493 {
494         struct timespec tv;
495         tv.tv_sec = millis / 1000;
496         tv.tv_nsec = millis % 1000 * 1000000;
497         do { } while (nanosleep(&tv, &tv) == EINTR);
498 }
499
500 void yieldThread()
501 {
502         sched_yield();
503 }
504
505 static void timedCondWait(pthread_cond_t *cond, pthread_mutex_t *mutex, s8 millis)
506 {
507         struct timeval now;
508         struct timespec desttime;
509         gettimeofday(&now, NULL);
510         desttime.tv_sec = millis / 1000;
511         desttime.tv_nsec = millis % 1000 * 1000000;
512         pthread_cond_timedwait(cond, mutex, &desttime);
513 }
514
515
516 #define NEUTRAL 0
517 #define LOCKED 1
518 #define WAITERS 2
519 #define BUSY 3
520
521 static void initExecutionEnvironment(ExecEnvironment *ee)
522 {
523         pthread_mutex_init(&ee->metaLockMutex, NULL);
524         pthread_cond_init(&ee->metaLockCond, NULL);
525         pthread_mutex_init(&ee->monitorLockMutex, NULL);
526         pthread_cond_init(&ee->monitorLockCond, NULL);
527 }
528
529 static void initLockRecord(monitorLockRecord *r, threadobject *t)
530 {
531         r->owner = t;
532         r->lockCount = 1;
533         r->queue = NULL;
534 }
535
536 void initLocks()
537 {
538         initThreadLocks(mainthreadobj);
539 }
540
541 static void initThreadLocks(threadobject *thread)
542 {
543         int i;
544
545         initExecutionEnvironment(&thread->ee);
546         for (i=0; i<INITIALLOCKRECORDS; i++) {
547                 monitorLockRecord *r = &thread->ee.lr[i];
548                 initLockRecord(r, thread);
549                 r->nextFree = &thread->ee.lr[i+1];
550         }
551         thread->ee.lr[i-1].nextFree = NULL;
552         thread->ee.firstLR = &thread->ee.lr[0];
553 }
554
555 static inline int lockState(long r)
556 {
557         return (int) r & 3;
558 }
559
560 static inline void *lockRecord(long r)
561 {
562         return (void*) (r & ~3L);
563 }
564
565 static inline long makeLockBits(void *r, long l)
566 {
567         return ((long) r) | l;
568 }
569
570 static lockRecordPool *allocLockRecordPool(threadobject *thread, int size)
571 {
572         lockRecordPool *p = mem_alloc(sizeof(lockRecordPoolHeader) + sizeof(monitorLockRecord) * size);
573         int i;
574
575         p->header.size = size;
576         for (i=0; i<size; i++) {
577                 initLockRecord(&p->lr[i], thread);
578                 p->lr[i].nextFree = &p->lr[i+1];
579         }
580         p->lr[i-1].nextFree = NULL;
581         return p;
582 }
583
584 static void freeLockRecordPools(lockRecordPool *pool)
585 {
586         while (pool) {
587                 lockRecordPool *n = pool->header.next;
588                 mem_free(pool, sizeof(lockRecordPoolHeader) + sizeof(monitorLockRecord) * pool->header.size);
589                 pool = n;
590         }
591 }
592
593 static monitorLockRecord *allocLockRecord(threadobject *t)
594 {
595         monitorLockRecord *r = t->ee.firstLR;
596
597         if (!r) {
598                 int poolsize = t->ee.lrpool ? t->ee.lrpool->header.size * 2 : INITIALLOCKRECORDS * 2;
599                 lockRecordPool *pool = allocLockRecordPool(t, poolsize);
600                 pool->header.next = t->ee.lrpool;
601                 t->ee.lrpool = pool;
602                 r = &pool->lr[0];
603         }
604         
605         t->ee.firstLR = r->nextFree;
606         return r;
607 }
608
609 static void recycleLockRecord(threadobject *t, monitorLockRecord *r)
610 {
611         r->nextFree = t->ee.firstLR;
612         t->ee.firstLR = r;
613 }
614
615 static monitorLockRecord *appendToQueue(monitorLockRecord *queue, monitorLockRecord *lr)
616 {
617         monitorLockRecord *queuestart = queue;
618         if (!queue)
619                 return lr;
620         while (queue->queue)
621                 queue = queue->queue;
622         queue->queue = lr;
623         return queuestart;
624 }
625
626 static monitorLockRecord *moveMyLRToFront(threadobject *t, monitorLockRecord *lr)
627 {
628         monitorLockRecord *pred = NULL;
629         monitorLockRecord *firstLR = lr;
630         while (lr->owner != t) {
631                 pred = lr;
632                 lr = lr->queue;
633         }
634         if (!pred)
635                 return lr;
636         pred->queue = lr->queue;
637         lr->queue = firstLR;
638         lr->storedBits = firstLR->storedBits;
639         return lr;
640 }
641
642 static long getMetaLockSlow(threadobject *t, long predBits);
643 static void releaseMetaLockSlow(threadobject *t, long releaseBits);
644
645 static long getMetaLock(threadobject *t, java_objectheader *o)
646 {
647         long busyBits = makeLockBits(t, BUSY);
648         long lockBits = atomic_swap(&o->monitorBits, busyBits);
649         return lockState(lockBits) != BUSY ? lockBits : getMetaLockSlow(t, lockBits);
650 }
651
652 static long getMetaLockSlow(threadobject *t, long predBits)
653 {
654         long bits;
655         threadobject *pred = lockRecord(predBits);
656         pthread_mutex_lock(&pred->ee.metaLockMutex);
657         if (!pred->ee.bitsForGrab) {
658                 pred->ee.succ = t;
659                 do {
660                         pthread_cond_wait(&pred->ee.metaLockCond, &pred->ee.metaLockMutex);
661                 } while (!t->ee.gotMetaLockSlow);
662                 t->ee.gotMetaLockSlow = false;
663                 bits = t->ee.metaLockBits;
664         } else {
665                 bits = pred->ee.metaLockBits;
666                 pred->ee.bitsForGrab = false;
667                 pthread_cond_signal(&pred->ee.metaLockCond);
668         }
669         pthread_mutex_unlock(&pred->ee.metaLockMutex);
670         return bits;
671 }
672
673 static void releaseMetaLock(threadobject *t, java_objectheader *o, long releaseBits)
674 {
675         long busyBits = makeLockBits(t, BUSY);
676         int locked = compare_and_swap(&o->monitorBits, busyBits, releaseBits) != 0;
677         
678         if (!locked)
679                 releaseMetaLockSlow(t, releaseBits);
680 }
681
682 static void releaseMetaLockSlow(threadobject *t, long releaseBits)
683 {
684         pthread_mutex_lock(&t->ee.metaLockMutex);
685         if (t->ee.succ) {
686                 assert(!t->ee.succ->ee.bitsForGrab);
687                 assert(!t->ee.bitsForGrab);
688                 assert(!t->ee.succ->ee.gotMetaLockSlow);
689                 t->ee.succ->ee.metaLockBits = releaseBits;
690                 t->ee.succ->ee.gotMetaLockSlow = true;
691                 t->ee.succ = NULL;
692                 pthread_cond_signal(&t->ee.metaLockCond);
693         } else {
694                 t->ee.metaLockBits = releaseBits;
695                 t->ee.bitsForGrab = true;
696                 do {
697                         pthread_cond_wait(&t->ee.metaLockCond, &t->ee.metaLockMutex);
698                 } while (t->ee.bitsForGrab);
699         }
700         pthread_mutex_unlock(&t->ee.metaLockMutex);
701 }
702
703 static void monitorEnterSlow(threadobject *t, java_objectheader *o, long r);
704
705 void monitorEnter(threadobject *t, java_objectheader *o)
706 {
707         long r = getMetaLock(t, o);
708         int state = lockState(r);
709
710         if (state == NEUTRAL) {
711                 monitorLockRecord *lr = allocLockRecord(t);
712                 lr->storedBits = r;
713                 releaseMetaLock(t, o, makeLockBits(lr, LOCKED));
714         } else if (state == LOCKED) {
715                 monitorLockRecord *ownerLR = lockRecord(r);
716                 if (ownerLR->owner == t) {
717                         ownerLR->lockCount++;
718                         releaseMetaLock(t, o, r);
719                 } else {
720                         monitorLockRecord *lr = allocLockRecord(t);
721                         ownerLR->queue = appendToQueue(ownerLR->queue, lr);
722                         monitorEnterSlow(t, o, r);
723                 }
724         } else if (state == WAITERS) {
725                 monitorLockRecord *lr = allocLockRecord(t);
726                 monitorLockRecord *firstWaiterLR = lockRecord(r);
727                 lr->queue = firstWaiterLR;
728                 lr->storedBits = firstWaiterLR->storedBits;
729                 releaseMetaLock(t, o, makeLockBits(lr, LOCKED));
730         }
731 }
732
733 static void monitorEnterSlow(threadobject *t, java_objectheader *o, long r)
734 {
735         monitorLockRecord *lr;
736         while (lockState(r) == LOCKED) {
737                 pthread_mutex_lock(&t->ee.monitorLockMutex);
738                 releaseMetaLock(t, o, r);
739                 pthread_cond_wait(&t->ee.monitorLockCond, &t->ee.monitorLockMutex);
740                 pthread_mutex_unlock(&t->ee.monitorLockMutex);
741                 r = getMetaLock(t, o);
742         }
743         assert(lockState(r) == WAITERS);
744         lr = moveMyLRToFront(t, lockRecord(r));
745         releaseMetaLock(t, o, makeLockBits(lr, LOCKED));
746 }
747
748 static void monitorExitSlow(threadobject *t, java_objectheader *o, monitorLockRecord *lr);
749
750 void monitorExit(threadobject *t, java_objectheader *o)
751 {
752         long r = getMetaLock(t, o);
753         monitorLockRecord *ownerLR = lockRecord(r);
754         int state = lockState(r);
755         if (state == LOCKED && ownerLR->owner == t) {
756                 assert(ownerLR->lockCount >= 1);
757                 if (ownerLR->lockCount == 1) {
758                         if (ownerLR->queue == NULL) {
759                                 assert(lockState(ownerLR->storedBits) == NEUTRAL);
760                                 releaseMetaLock(t, o, ownerLR->storedBits);
761                         } else {
762                                 ownerLR->queue->storedBits = ownerLR->storedBits;
763                                 monitorExitSlow(t, o, ownerLR->queue);
764                                 ownerLR->queue = NULL;
765                         }
766                         recycleLockRecord(t, ownerLR);
767                 } else {
768                         ownerLR->lockCount--;
769                         releaseMetaLock(t, o, r);
770                 }
771         } else {
772                 releaseMetaLock(t, o, r);
773                 panic("Illegal monitor exception");
774         }
775 }
776
777 static threadobject *wakeupEE(monitorLockRecord *lr)
778 {
779         while (lr->queue && lr->queue->owner->ee.isWaitingForNotify)
780                 lr = lr->queue;
781         return lr->owner;
782 }
783
784 static void monitorExitSlow(threadobject *t, java_objectheader *o, monitorLockRecord *lr)
785 {
786         threadobject *wakeEE = wakeupEE(lr);
787         if (wakeEE) {
788                 pthread_mutex_lock(&wakeEE->ee.monitorLockMutex);
789                 releaseMetaLock(t, o, makeLockBits(lr, WAITERS));
790                 pthread_cond_signal(&wakeEE->ee.monitorLockCond);
791                 pthread_mutex_unlock(&wakeEE->ee.monitorLockMutex);
792         } else {
793                 releaseMetaLock(t, o, makeLockBits(lr, WAITERS));
794         }
795 }
796
797 void monitorWait(threadobject *t, java_objectheader *o, s8 millis)
798 {
799         long r = getMetaLock(t, o);
800         monitorLockRecord *ownerLR = lockRecord(r);
801         int state = lockState(r);
802         if (state == LOCKED && ownerLR->owner == t) {
803                 pthread_mutex_lock(&t->ee.monitorLockMutex);
804                 t->ee.isWaitingForNotify = true;
805                 monitorExitSlow(t, o, ownerLR);
806                 if (millis == -1)
807                         pthread_cond_wait(&t->ee.monitorLockCond, &t->ee.monitorLockMutex);
808                 else
809                         timedCondWait(&t->ee.monitorLockCond, &t->ee.monitorLockMutex, millis);
810                 t->ee.isWaitingForNotify = false;
811                 pthread_mutex_unlock(&t->ee.monitorLockMutex);
812                 r = getMetaLock(t, o);
813                 monitorEnterSlow(t, o, r);
814         } else {
815                 releaseMetaLock(t, o, r);
816                 panic("Illegal monitor exception");
817         }
818 }
819
820 static void notifyOneOrAll(threadobject *t, java_objectheader *o, bool one)
821 {
822         long r = getMetaLock(t, o);
823         monitorLockRecord *ownerLR = lockRecord(r);
824         int state = lockState(r);
825         if (state == LOCKED && ownerLR->owner == t) {
826                 monitorLockRecord *q = ownerLR->queue;
827                 while (q) {
828                         if (q->owner->ee.isWaitingForNotify) {
829                                 q->owner->ee.isWaitingForNotify = false;
830                                 if (one)
831                                         break;
832                         }
833                         q = q->queue;
834                 }
835                 releaseMetaLock(t, o, r);
836         } else {
837                 releaseMetaLock(t, o, r);
838                 panic("Illegal monitor exception");
839         }
840 }
841
842 void wait_cond_for_object(java_objectheader *o, s8 time)
843 {
844         threadobject *t = (threadobject*) THREADOBJECT;
845         monitorWait(t, o, time);
846 }
847
848 void signal_cond_for_object(java_objectheader *o)
849 {
850         threadobject *t = (threadobject*) THREADOBJECT;
851         notifyOneOrAll(t, o, true);
852 }
853
854 void broadcast_cond_for_object(java_objectheader *o)
855 {
856         threadobject *t = (threadobject*) THREADOBJECT;
857         notifyOneOrAll(t, o, false);
858 }
859
860 #endif
861
862
863 /*
864  * These are local overrides for various environment variables in Emacs.
865  * Please do not remove this and leave it at the end of the file, where
866  * Emacs will automagically detect them.
867  * ---------------------------------------------------------------------
868  * Local variables:
869  * mode: c
870  * indent-tabs-mode: t
871  * c-basic-offset: 4
872  * tab-width: 4
873  * End:
874  */