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 void thread_addstaticcritical()
138 threadcritnode *n = &asm_criticalsections;
140 while (n->mcodebegin)
141 thread_registercritical(n++);
144 static pthread_mutex_t threadlistlock = PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP;
146 static pthread_mutex_t stopworldlock = PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP;
147 volatile int stopworldwhere;
149 static sem_t suspend_ack;
152 * where - 1 from within GC
155 void lock_stopworld(int where)
157 pthread_mutex_lock(&stopworldlock);
158 stopworldwhere = where;
161 void unlock_stopworld()
164 pthread_mutex_unlock(&stopworldlock);
167 /* Caller must hold threadlistlock */
168 static int cast_sendsignals(int sig, int count)
171 threadobject *tobj = mainthreadobj;
172 nativethread *infoself = THREADINFO;
177 tobj = tobj->info.next;
178 } while (tobj != mainthreadobj);
181 nativethread *info = &tobj->info;
182 if (info != infoself)
183 pthread_kill(info->tid, sig);
184 tobj = tobj->info.next;
185 } while (tobj != mainthreadobj);
190 void cast_stopworld()
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);
201 void cast_startworld()
203 pthread_mutex_lock(&threadlistlock);
204 cast_sendsignals(GC_signum2(), -1);
205 pthread_mutex_unlock(&threadlistlock);
209 static void sigsuspend_handler(ucontext_t *ctx)
214 thread_restartcriticalsection(ctx);
216 sem_post(&suspend_ack);
220 sigdelset(&sigs, sig);
224 int cacao_suspendhandler(ucontext_t *ctx)
226 if (stopworldwhere != 2)
229 sigsuspend_handler(ctx);
233 static void setthreadobject(threadobject *thread)
235 #if !defined(HAVE___THREAD)
236 pthread_setspecific(tkey_threadinfo, thread);
243 * Initialize threads.
248 /* Allocate something so the garbage collector's signal handlers are */
250 heap_allocate(1, false, NULL);
252 mainthreadobj = NEW(threadobject);
253 memset(mainthreadobj, 0, sizeof(threadobject));
254 #if !defined(HAVE___THREAD)
255 pthread_key_create(&tkey_threadinfo, NULL);
257 setthreadobject(mainthreadobj);
259 criticaltree = avl_create(criticalcompare, NULL, NULL);
260 thread_addstaticcritical();
261 sem_init(&suspend_ack, 0, 0);
264 static pthread_attr_t threadattr;
265 static void freeLockRecordPools(lockRecordPool *);
268 initThreads(u1 *stackbottom)
270 classinfo *threadclass;
271 classinfo *threadgroupclass;
272 java_lang_Thread *mainthread;
273 threadobject *tempthread = mainthreadobj;
275 threadclass = class_new(utf_new_char("java/lang/Thread"));
276 class_load(threadclass);
277 class_link(threadclass);
280 freeLockRecordPools(mainthreadobj->ee.lrpool);
281 threadclass->instancesize = sizeof(threadobject);
283 mainthreadobj = (threadobject *) builtin_new(threadclass);
284 assert(mainthreadobj);
286 FREE(tempthread, threadobject);
287 initThread(&mainthreadobj->o);
289 #if !defined(HAVE___THREAD)
290 pthread_setspecific(tkey_threadinfo, mainthreadobj);
292 threadobj = mainthreadobj;
295 mainthread = &mainthreadobj->o;
297 mainthreadobj->info.next = mainthreadobj;
298 mainthreadobj->info.prev = mainthreadobj;
300 mainthread->name=javastring_new(utf_new_char("main"));
302 /* Allocate and init ThreadGroup */
303 threadgroupclass = class_new(utf_new_char("java/lang/ThreadGroup"));
304 class_load(threadgroupclass);
305 class_link(threadgroupclass);
308 (java_lang_ThreadGroup *) native_new_and_init(threadgroupclass);
309 assert(mainthread->group != 0);
311 pthread_attr_init(&threadattr);
312 pthread_attr_setdetachstate(&threadattr, PTHREAD_CREATE_DETACHED);
315 void initThread(java_lang_Thread *t)
317 nativethread *info = &((threadobject*) t)->info;
318 pthread_mutex_init(&info->joinMutex, NULL);
319 pthread_cond_init(&info->joinCond, NULL);
322 static void initThreadLocks(threadobject *);
325 threadobject *thread;
329 static void *threadstartup(void *t)
331 startupinfo *startup = t;
333 threadobject *thread = startup->thread;
334 sem_t *psem = startup->psem;
335 nativethread *info = &thread->info;
339 setthreadobject(thread);
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);
348 initThreadLocks(thread);
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"));
357 panic("Cannot find method \'void run ()\'");
359 asm_calljavafunction(method, thread, NULL, NULL, NULL);
361 if (info->_exceptionptr) {
362 utf_display_classname((info->_exceptionptr)->vftbl->class->name);
366 freeLockRecordPools(thread->ee.lrpool);
368 pthread_mutex_lock(&threadlistlock);
369 info->next->info.prev = info->prev;
370 info->prev->info.next = info->next;
371 pthread_mutex_unlock(&threadlistlock);
373 pthread_mutex_lock(&info->joinMutex);
375 pthread_mutex_unlock(&info->joinMutex);
376 pthread_cond_broadcast(&info->joinCond);
381 void startThread(threadobject *t)
383 nativethread *info = &t->info;
390 sem_init(&sem, 0, 0);
392 if (pthread_create(&info->tid, &threadattr, threadstartup, &startup))
393 panic("pthread_create failed");
395 /* Wait here until thread has entered itself into the thread list */
400 void joinAllThreads()
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);
408 pthread_cond_wait(&info->joinCond, &info->joinMutex);
409 pthread_mutex_unlock(&info->joinMutex);
410 pthread_mutex_lock(&threadlistlock);
412 pthread_mutex_unlock(&threadlistlock);
415 bool aliveThread(java_lang_Thread *t)
417 return ((threadobject*) t)->info.tid != 0;
420 void sleepThread(s8 millis)
423 tv.tv_sec = millis / 1000;
424 tv.tv_nsec = millis % 1000 * 1000000;
425 do { } while (nanosleep(&tv, &tv) == EINTR);
433 static void timedCondWait(pthread_cond_t *cond, pthread_mutex_t *mutex, s8 millis)
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);
449 static void initExecutionEnvironment(ExecEnvironment *ee)
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);
457 static void initLockRecord(monitorLockRecord *r, threadobject *t)
466 initThreadLocks(mainthreadobj);
469 static void initThreadLocks(threadobject *thread)
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];
479 thread->ee.lr[i-1].nextFree = NULL;
480 thread->ee.firstLR = &thread->ee.lr[0];
483 static inline int lockState(long r)
488 static inline void *lockRecord(long r)
490 return (void*) (r & ~3L);
493 static inline long makeLockBits(void *r, long l)
495 return ((long) r) | l;
498 static lockRecordPool *allocLockRecordPool(threadobject *thread, int size)
500 lockRecordPool *p = mem_alloc(sizeof(lockRecordPoolHeader) + sizeof(monitorLockRecord) * size);
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];
508 p->lr[i-1].nextFree = NULL;
512 static void freeLockRecordPools(lockRecordPool *pool)
515 lockRecordPool *n = pool->header.next;
516 mem_free(pool, sizeof(lockRecordPoolHeader) + sizeof(monitorLockRecord) * pool->header.size);
521 static monitorLockRecord *allocLockRecord(threadobject *t)
523 monitorLockRecord *r = t->ee.firstLR;
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;
533 t->ee.firstLR = r->nextFree;
537 static void recycleLockRecord(threadobject *t, monitorLockRecord *r)
539 r->nextFree = t->ee.firstLR;
543 static monitorLockRecord *appendToQueue(monitorLockRecord *queue, monitorLockRecord *lr)
545 monitorLockRecord *queuestart = queue;
549 queue = queue->queue;
554 static monitorLockRecord *moveMyLRToFront(threadobject *t, monitorLockRecord *lr)
556 monitorLockRecord *pred = NULL;
557 monitorLockRecord *firstLR = lr;
558 while (lr->owner != t) {
564 pred->queue = lr->queue;
566 lr->storedBits = firstLR->storedBits;
570 static long getMetaLockSlow(threadobject *t, long predBits);
571 static void releaseMetaLockSlow(threadobject *t, long releaseBits);
573 static long getMetaLock(threadobject *t, java_objectheader *o)
575 long busyBits = makeLockBits(t, BUSY);
576 long lockBits = atomic_swap(&o->monitorBits, busyBits);
577 return lockState(lockBits) != BUSY ? lockBits : getMetaLockSlow(t, lockBits);
580 static long getMetaLockSlow(threadobject *t, long predBits)
583 threadobject *pred = lockRecord(predBits);
584 pthread_mutex_lock(&pred->ee.metaLockMutex);
585 if (!pred->ee.bitsForGrab) {
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;
593 bits = pred->ee.metaLockBits;
594 pred->ee.bitsForGrab = false;
595 pthread_cond_signal(&pred->ee.metaLockCond);
597 pthread_mutex_unlock(&pred->ee.metaLockMutex);
601 static void releaseMetaLock(threadobject *t, java_objectheader *o, long releaseBits)
603 long busyBits = makeLockBits(t, BUSY);
604 int locked = compare_and_swap(&o->monitorBits, busyBits, releaseBits) != 0;
607 releaseMetaLockSlow(t, releaseBits);
610 static void releaseMetaLockSlow(threadobject *t, long releaseBits)
612 pthread_mutex_lock(&t->ee.metaLockMutex);
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;
620 pthread_cond_signal(&t->ee.metaLockCond);
622 t->ee.metaLockBits = releaseBits;
623 t->ee.bitsForGrab = true;
625 pthread_cond_wait(&t->ee.metaLockCond, &t->ee.metaLockMutex);
626 } while (t->ee.bitsForGrab);
628 pthread_mutex_unlock(&t->ee.metaLockMutex);
631 static void monitorEnterSlow(threadobject *t, java_objectheader *o, long r);
633 void monitorEnter(threadobject *t, java_objectheader *o)
635 long r = getMetaLock(t, o);
636 int state = lockState(r);
638 if (state == NEUTRAL) {
639 monitorLockRecord *lr = allocLockRecord(t);
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);
648 monitorLockRecord *lr = allocLockRecord(t);
649 ownerLR->queue = appendToQueue(ownerLR->queue, lr);
650 monitorEnterSlow(t, o, r);
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));
661 static void monitorEnterSlow(threadobject *t, java_objectheader *o, long r)
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);
671 assert(lockState(r) == WAITERS);
672 lr = moveMyLRToFront(t, lockRecord(r));
673 releaseMetaLock(t, o, makeLockBits(lr, LOCKED));
676 static void monitorExitSlow(threadobject *t, java_objectheader *o, monitorLockRecord *lr);
678 void monitorExit(threadobject *t, java_objectheader *o)
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);
690 ownerLR->queue->storedBits = ownerLR->storedBits;
691 monitorExitSlow(t, o, ownerLR->queue);
692 ownerLR->queue = NULL;
694 recycleLockRecord(t, ownerLR);
696 ownerLR->lockCount--;
697 releaseMetaLock(t, o, r);
700 releaseMetaLock(t, o, r);
701 panic("Illegal monitor exception");
705 static threadobject *wakeupEE(monitorLockRecord *lr)
707 while (lr->queue && lr->queue->owner->ee.isWaitingForNotify)
712 static void monitorExitSlow(threadobject *t, java_objectheader *o, monitorLockRecord *lr)
714 threadobject *wakeEE = wakeupEE(lr);
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);
721 releaseMetaLock(t, o, makeLockBits(lr, WAITERS));
725 void monitorWait(threadobject *t, java_objectheader *o, s8 millis)
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);
735 pthread_cond_wait(&t->ee.monitorLockCond, &t->ee.monitorLockMutex);
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);
743 releaseMetaLock(t, o, r);
744 panic("Illegal monitor exception");
748 static void notifyOneOrAll(threadobject *t, java_objectheader *o, bool one)
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;
756 if (q->owner->ee.isWaitingForNotify) {
757 q->owner->ee.isWaitingForNotify = false;
763 releaseMetaLock(t, o, r);
765 releaseMetaLock(t, o, r);
766 panic("Illegal monitor exception");
770 void wait_cond_for_object(java_objectheader *o, s8 time)
772 threadobject *t = (threadobject*) THREADOBJECT;
773 monitorWait(t, o, time);
776 void signal_cond_for_object(java_objectheader *o)
778 threadobject *t = (threadobject*) THREADOBJECT;
779 notifyOneOrAll(t, o, true);
782 void broadcast_cond_for_object(java_objectheader *o)
784 threadobject *t = (threadobject*) THREADOBJECT;
785 notifyOneOrAll(t, o, false);
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 * ---------------------------------------------------------------------
798 * indent-tabs-mode: t