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