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