3 #if defined(NATIVE_THREADS)
24 #include "toolbox/logging.h"
25 #include "toolbox/memory.h"
26 #include "toolbox/avl.h"
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"
35 #include <semaphore.h>
37 #if defined(__LINUX__)
38 #define GC_LINUX_THREADS
39 #include "../mm/boehm-gc/include/gc.h"
42 #include "machine-instr.h"
44 static struct avl_table *criticaltree;
45 static threadobject *mainthreadobj;
48 pthread_key_t tkey_threadinfo;
50 __thread threadobject *threadobj;
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;
59 pthread_mutex_lock(&cast_mutex);
64 pthread_mutex_unlock(&cast_mutex);
69 pthread_mutex_lock(&compiler_mutex);
72 void compiler_unlock()
74 pthread_mutex_unlock(&compiler_mutex);
79 pthread_mutex_lock(&tablelock);
84 pthread_mutex_unlock(&tablelock);
87 static int criticalcompare(const void *pa, const void *pb, void *param)
89 const threadcritnode *na = pa;
90 const threadcritnode *nb = pb;
92 if (na->mcodebegin < nb->mcodebegin)
94 if (na->mcodebegin > nb->mcodebegin)
99 static const threadcritnode *findcritical(u1 *mcodeptr)
101 struct avl_node *n = criticaltree->avl_root;
102 const threadcritnode *m = NULL;
107 const threadcritnode *d = n->avl_data;
108 if (mcodeptr == d->mcodebegin)
110 if (mcodeptr < d->mcodebegin) {
116 if (n->avl_link[1]) {
125 void thread_registercritical(threadcritnode *n)
127 avl_insert(criticaltree, n);
130 u1 *thread_checkcritical(u1 *mcodeptr)
132 const threadcritnode *n = findcritical(mcodeptr);
133 return (n && mcodeptr < n->mcodeend && mcodeptr > n->mcodebegin) ? n->mcoderestart : NULL;
136 static pthread_mutex_t threadlistlock = PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP;
138 static pthread_mutex_t stopworldlock = PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP;
139 volatile int stopworldwhere;
141 static sem_t suspend_ack;
144 * where - 1 from within GC
147 void lock_stopworld(int where)
149 pthread_mutex_lock(&stopworldlock);
150 stopworldwhere = where;
153 void unlock_stopworld()
156 pthread_mutex_unlock(&stopworldlock);
159 /* Caller must hold threadlistlock */
160 static int cast_sendsignals(int sig, int count)
163 threadobject *tobj = mainthreadobj;
164 nativethread *infoself = THREADINFO;
169 tobj = tobj->info.next;
170 } while (tobj != mainthreadobj);
173 nativethread *info = &tobj->info;
174 if (info != infoself)
175 pthread_kill(info->tid, sig);
176 tobj = tobj->info.next;
177 } while (tobj != mainthreadobj);
182 void cast_stopworld()
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);
193 void cast_startworld()
195 pthread_mutex_lock(&threadlistlock);
196 cast_sendsignals(GC_signum2(), -1);
197 pthread_mutex_unlock(&threadlistlock);
201 static void sigsuspend_handler(ucontext_t *ctx)
206 thread_restartcriticalsection(ctx);
208 sem_post(&suspend_ack);
212 sigdelset(&sigs, sig);
216 int cacao_suspendhandler(ucontext_t *ctx)
218 if (stopworldwhere != 2)
221 sigsuspend_handler(ctx);
225 static void setthreadobject(threadobject *thread)
227 #if !defined(HAVE___THREAD)
228 pthread_setspecific(tkey_threadinfo, thread);
235 * Initialize threads.
240 /* Allocate something so the garbage collector's signal handlers are */
242 heap_allocate(1, false, NULL);
244 mainthreadobj = NEW(threadobject);
245 memset(mainthreadobj, 0, sizeof(threadobject));
246 #if !defined(HAVE___THREAD)
247 pthread_key_create(&tkey_threadinfo, NULL);
249 setthreadobject(mainthreadobj);
251 criticaltree = avl_create(criticalcompare, NULL, NULL);
252 sem_init(&suspend_ack, 0, 0);
255 static pthread_attr_t threadattr;
256 static void freeLockRecordPools(lockRecordPool *);
259 initThreads(u1 *stackbottom)
261 classinfo *threadclass;
262 classinfo *threadgroupclass;
263 java_lang_Thread *mainthread;
264 threadobject *tempthread = mainthreadobj;
266 threadclass = class_new(utf_new_char("java/lang/Thread"));
267 class_load(threadclass);
268 class_link(threadclass);
271 freeLockRecordPools(mainthreadobj->ee.lrpool);
272 threadclass->instancesize = sizeof(threadobject);
274 mainthreadobj = (threadobject *) builtin_new(threadclass);
275 assert(mainthreadobj);
277 FREE(tempthread, threadobject);
278 initThread(&mainthreadobj->o);
280 #if !defined(HAVE___THREAD)
281 pthread_setspecific(tkey_threadinfo, mainthreadobj);
283 threadobj = mainthreadobj;
286 mainthread = &mainthreadobj->o;
288 mainthreadobj->info.next = mainthreadobj;
289 mainthreadobj->info.prev = mainthreadobj;
291 mainthread->name=javastring_new(utf_new_char("main"));
293 /* Allocate and init ThreadGroup */
294 threadgroupclass = class_new(utf_new_char("java/lang/ThreadGroup"));
295 class_load(threadgroupclass);
296 class_link(threadgroupclass);
299 (java_lang_ThreadGroup *) native_new_and_init(threadgroupclass);
300 assert(mainthread->group != 0);
302 pthread_attr_init(&threadattr);
303 pthread_attr_setdetachstate(&threadattr, PTHREAD_CREATE_DETACHED);
306 void initThread(java_lang_Thread *t)
308 nativethread *info = &((threadobject*) t)->info;
309 pthread_mutex_init(&info->joinMutex, NULL);
310 pthread_cond_init(&info->joinCond, NULL);
313 static void initThreadLocks(threadobject *);
316 threadobject *thread;
320 static void *threadstartup(void *t)
322 startupinfo *startup = t;
324 threadobject *thread = startup->thread;
325 sem_t *psem = startup->psem;
326 nativethread *info = &thread->info;
330 setthreadobject(thread);
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);
339 initThreadLocks(thread);
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"));
348 panic("Cannot find method \'void run ()\'");
350 asm_calljavafunction(method, thread, NULL, NULL, NULL);
352 if (info->_exceptionptr) {
353 utf_display_classname((info->_exceptionptr)->vftbl->class->name);
357 freeLockRecordPools(thread->ee.lrpool);
359 pthread_mutex_lock(&threadlistlock);
360 info->next->info.prev = info->prev;
361 info->prev->info.next = info->next;
362 pthread_mutex_unlock(&threadlistlock);
364 pthread_mutex_lock(&info->joinMutex);
366 pthread_mutex_unlock(&info->joinMutex);
367 pthread_cond_broadcast(&info->joinCond);
372 void startThread(threadobject *t)
374 nativethread *info = &t->info;
381 sem_init(&sem, 0, 0);
383 if (pthread_create(&info->tid, &threadattr, threadstartup, &startup))
384 panic("pthread_create failed");
386 /* Wait here until thread has entered itself into the thread list */
391 void joinAllThreads()
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);
399 pthread_cond_wait(&info->joinCond, &info->joinMutex);
400 pthread_mutex_unlock(&info->joinMutex);
401 pthread_mutex_lock(&threadlistlock);
403 pthread_mutex_unlock(&threadlistlock);
406 bool aliveThread(java_lang_Thread *t)
408 return ((threadobject*) t)->info.tid != 0;
411 void sleepThread(s8 millis)
414 tv.tv_sec = millis / 1000;
415 tv.tv_nsec = millis % 1000 * 1000000;
416 do { } while (nanosleep(&tv, &tv) == EINTR);
424 static void timedCondWait(pthread_cond_t *cond, pthread_mutex_t *mutex, s8 millis)
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);
440 static void initExecutionEnvironment(ExecEnvironment *ee)
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);
448 static void initLockRecord(monitorLockRecord *r, threadobject *t)
457 initThreadLocks(mainthreadobj);
460 static void initThreadLocks(threadobject *thread)
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];
470 thread->ee.lr[i-1].nextFree = NULL;
471 thread->ee.firstLR = &thread->ee.lr[0];
474 static inline int lockState(long r)
479 static inline void *lockRecord(long r)
481 return (void*) (r & ~3L);
484 static inline long makeLockBits(void *r, long l)
486 return ((long) r) | l;
489 static lockRecordPool *allocLockRecordPool(threadobject *thread, int size)
491 lockRecordPool *p = mem_alloc(sizeof(lockRecordPoolHeader) + sizeof(monitorLockRecord) * size);
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];
499 p->lr[i-1].nextFree = NULL;
503 static void freeLockRecordPools(lockRecordPool *pool)
506 lockRecordPool *n = pool->header.next;
507 mem_free(pool, sizeof(lockRecordPoolHeader) + sizeof(monitorLockRecord) * pool->header.size);
512 static monitorLockRecord *allocLockRecord(threadobject *t)
514 monitorLockRecord *r = t->ee.firstLR;
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;
524 t->ee.firstLR = r->nextFree;
528 static void recycleLockRecord(threadobject *t, monitorLockRecord *r)
530 r->nextFree = t->ee.firstLR;
534 static monitorLockRecord *appendToQueue(monitorLockRecord *queue, monitorLockRecord *lr)
536 monitorLockRecord *queuestart = queue;
540 queue = queue->queue;
545 static monitorLockRecord *moveMyLRToFront(threadobject *t, monitorLockRecord *lr)
547 monitorLockRecord *pred = NULL;
548 monitorLockRecord *firstLR = lr;
549 while (lr->owner != t) {
555 pred->queue = lr->queue;
557 lr->storedBits = firstLR->storedBits;
561 static long getMetaLockSlow(threadobject *t, long predBits);
562 static void releaseMetaLockSlow(threadobject *t, long releaseBits);
564 static long getMetaLock(threadobject *t, java_objectheader *o)
566 long busyBits = makeLockBits(t, BUSY);
567 long lockBits = atomic_swap(&o->monitorBits, busyBits);
568 return lockState(lockBits) != BUSY ? lockBits : getMetaLockSlow(t, lockBits);
571 static long getMetaLockSlow(threadobject *t, long predBits)
574 threadobject *pred = lockRecord(predBits);
575 pthread_mutex_lock(&pred->ee.metaLockMutex);
576 if (!pred->ee.bitsForGrab) {
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;
584 bits = pred->ee.metaLockBits;
585 pred->ee.bitsForGrab = false;
586 pthread_cond_signal(&pred->ee.metaLockCond);
588 pthread_mutex_unlock(&pred->ee.metaLockMutex);
592 static void releaseMetaLock(threadobject *t, java_objectheader *o, long releaseBits)
594 long busyBits = makeLockBits(t, BUSY);
595 int locked = compare_and_swap(&o->monitorBits, busyBits, releaseBits) != 0;
598 releaseMetaLockSlow(t, releaseBits);
601 static void releaseMetaLockSlow(threadobject *t, long releaseBits)
603 pthread_mutex_lock(&t->ee.metaLockMutex);
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;
611 pthread_cond_signal(&t->ee.metaLockCond);
613 t->ee.metaLockBits = releaseBits;
614 t->ee.bitsForGrab = true;
616 pthread_cond_wait(&t->ee.metaLockCond, &t->ee.metaLockMutex);
617 } while (t->ee.bitsForGrab);
619 pthread_mutex_unlock(&t->ee.metaLockMutex);
622 static void monitorEnterSlow(threadobject *t, java_objectheader *o, long r);
624 void monitorEnter(threadobject *t, java_objectheader *o)
626 long r = getMetaLock(t, o);
627 int state = lockState(r);
629 if (state == NEUTRAL) {
630 monitorLockRecord *lr = allocLockRecord(t);
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);
639 monitorLockRecord *lr = allocLockRecord(t);
640 ownerLR->queue = appendToQueue(ownerLR->queue, lr);
641 monitorEnterSlow(t, o, r);
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));
652 static void monitorEnterSlow(threadobject *t, java_objectheader *o, long r)
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);
662 assert(lockState(r) == WAITERS);
663 lr = moveMyLRToFront(t, lockRecord(r));
664 releaseMetaLock(t, o, makeLockBits(lr, LOCKED));
667 static void monitorExitSlow(threadobject *t, java_objectheader *o, monitorLockRecord *lr);
669 void monitorExit(threadobject *t, java_objectheader *o)
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);
681 ownerLR->queue->storedBits = ownerLR->storedBits;
682 monitorExitSlow(t, o, ownerLR->queue);
683 ownerLR->queue = NULL;
685 recycleLockRecord(t, ownerLR);
687 ownerLR->lockCount--;
688 releaseMetaLock(t, o, r);
691 releaseMetaLock(t, o, r);
692 panic("Illegal monitor exception");
696 static threadobject *wakeupEE(monitorLockRecord *lr)
698 while (lr->queue && lr->queue->owner->ee.isWaitingForNotify)
703 static void monitorExitSlow(threadobject *t, java_objectheader *o, monitorLockRecord *lr)
705 threadobject *wakeEE = wakeupEE(lr);
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);
712 releaseMetaLock(t, o, makeLockBits(lr, WAITERS));
716 void monitorWait(threadobject *t, java_objectheader *o, s8 millis)
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);
726 pthread_cond_wait(&t->ee.monitorLockCond, &t->ee.monitorLockMutex);
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);
734 releaseMetaLock(t, o, r);
735 panic("Illegal monitor exception");
739 static void notifyOneOrAll(threadobject *t, java_objectheader *o, bool one)
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;
747 if (q->owner->ee.isWaitingForNotify) {
748 q->owner->ee.isWaitingForNotify = false;
754 releaseMetaLock(t, o, r);
756 releaseMetaLock(t, o, r);
757 panic("Illegal monitor exception");
761 void wait_cond_for_object(java_objectheader *o, s8 time)
763 threadobject *t = (threadobject*) THREADOBJECT;
764 monitorWait(t, o, time);
767 void signal_cond_for_object(java_objectheader *o)
769 threadobject *t = (threadobject*) THREADOBJECT;
770 notifyOneOrAll(t, o, true);
773 void broadcast_cond_for_object(java_objectheader *o)
775 threadobject *t = (threadobject*) THREADOBJECT;
776 notifyOneOrAll(t, o, false);
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 * ---------------------------------------------------------------------
789 * indent-tabs-mode: t