3 #if defined(NATIVE_THREADS)
23 #include "toolbox/loging.h"
24 #include "toolbox/memory.h"
25 #include "toolbox/avl.h"
28 #include "nat/java_lang_Object.h"
29 #include "nat/java_lang_Throwable.h"
30 #include "nat/java_lang_Thread.h"
31 #include "nat/java_lang_ThreadGroup.h"
34 #include <semaphore.h>
36 #if defined(__LINUX__)
37 #define GC_LINUX_THREADS
38 #include "../mm/boehm-gc/include/gc.h"
41 #include "machine-instr.h"
43 static struct avl_table *criticaltree;
44 static threadobject *mainthreadobj;
47 pthread_key_t tkey_threadinfo;
49 __thread threadobject *threadobj;
52 static pthread_mutex_t cast_mutex = PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP;
53 static pthread_mutex_t compiler_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
54 static pthread_mutex_t tablelock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
58 pthread_mutex_lock(&cast_mutex);
63 pthread_mutex_unlock(&cast_mutex);
68 pthread_mutex_lock(&compiler_mutex);
71 void compiler_unlock()
73 pthread_mutex_unlock(&compiler_mutex);
78 pthread_mutex_lock(&tablelock);
83 pthread_mutex_unlock(&tablelock);
86 static int criticalcompare(const void *pa, const void *pb, void *param)
88 const threadcritnode *na = pa;
89 const threadcritnode *nb = pb;
91 if (na->mcodebegin < nb->mcodebegin)
93 if (na->mcodebegin > nb->mcodebegin)
98 static const threadcritnode *findcritical(u1 *mcodeptr)
100 struct avl_node *n = criticaltree->avl_root;
101 const threadcritnode *m = NULL;
106 const threadcritnode *d = n->avl_data;
107 if (mcodeptr == d->mcodebegin)
109 if (mcodeptr < d->mcodebegin) {
115 if (n->avl_link[1]) {
124 void thread_registercritical(threadcritnode *n)
126 avl_insert(criticaltree, n);
129 static u1 *thread_checkcritical(u1 *mcodeptr)
131 const threadcritnode *n = findcritical(mcodeptr);
132 return (n && mcodeptr < n->mcodeend) ? n->mcodebegin : NULL;
135 static pthread_mutex_t threadlistlock = PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP;
137 static pthread_mutex_t stopworldlock = PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP;
138 volatile int stopworldwhere;
140 static sem_t suspend_ack;
143 * where - 1 from within GC
146 void lock_stopworld(int where)
148 pthread_mutex_lock(&stopworldlock);
149 stopworldwhere = where;
152 void unlock_stopworld()
155 pthread_mutex_unlock(&stopworldlock);
158 /* Caller must hold threadlistlock */
159 static int cast_sendsignals(int sig, int count)
162 threadobject *tobj = mainthreadobj;
163 nativethread *infoself = THREADINFO;
168 tobj = tobj->info.next;
169 } while (tobj != mainthreadobj);
172 nativethread *info = &tobj->info;
173 if (info != infoself)
174 pthread_kill(info->tid, sig);
175 tobj = tobj->info.next;
176 } while (tobj != mainthreadobj);
181 void cast_stopworld()
185 pthread_mutex_lock(&threadlistlock);
186 count = cast_sendsignals(GC_signum1(), 0);
187 for (i=0; i<count; i++)
188 sem_wait(&suspend_ack);
189 pthread_mutex_unlock(&threadlistlock);
192 void cast_startworld()
194 pthread_mutex_lock(&threadlistlock);
195 cast_sendsignals(GC_signum2(), -1);
196 pthread_mutex_unlock(&threadlistlock);
200 static void sigsuspend_handler(struct sigcontext *ctx)
207 if ((critical = thread_checkcritical((void*) ctx->eip)) != NULL)
208 ctx->eip = (long) critical;
211 sem_post(&suspend_ack);
215 sigdelset(&sigs, sig);
219 int cacao_suspendhandler(struct sigcontext *ctx)
221 if (stopworldwhere != 2)
224 sigsuspend_handler(ctx);
228 static void setthreadobject(threadobject *thread)
230 #if !defined(HAVE___THREAD)
231 pthread_setspecific(tkey_threadinfo, thread);
238 * Initialize threads.
245 /* Allocate something so the garbage collector's signal handlers are */
247 heap_allocate(1, false, NULL);
249 mainthreadobj = NEW(threadobject);
250 memset(mainthreadobj, 0, sizeof(threadobject));
251 #if !defined(HAVE___THREAD)
252 pthread_key_create(&tkey_threadinfo, NULL);
254 setthreadobject(mainthreadobj);
256 criticaltree = avl_create(criticalcompare, NULL, NULL);
257 sem_init(&suspend_ack, 0, 0);
260 static void freeLockRecordPools(lockRecordPool *);
263 initThreads(u1 *stackbottom)
265 classinfo *threadclass;
266 java_lang_Thread *mainthread;
267 threadobject *tempthread = mainthreadobj;
269 threadclass = loader_load_sysclass(NULL,utf_new_char("java/lang/Thread"));
271 freeLockRecordPools(mainthreadobj->ee.lrpool);
272 threadclass->instancesize = sizeof(threadobject);
273 mainthreadobj = (threadobject*) builtin_new(threadclass);
274 assert(mainthreadobj);
275 FREE(tempthread, threadobject);
276 initThread(&mainthreadobj->o);
278 #if !defined(HAVE___THREAD)
279 pthread_setspecific(tkey_threadinfo, mainthreadobj);
281 threadobj = mainthreadobj;
284 mainthread = &mainthreadobj->o;
286 mainthreadobj->info.next = mainthreadobj;
287 mainthreadobj->info.prev = mainthreadobj;
289 mainthread->name=javastring_new(utf_new_char("main"));
291 /* Allocate and init ThreadGroup */
292 mainthread->group = (java_lang_ThreadGroup*)native_new_and_init(loader_load(utf_new_char("java/lang/ThreadGroup")));
293 assert(mainthread->group != 0);
296 void initThread(java_lang_Thread *t)
298 nativethread *info = &((threadobject*) t)->info;
299 pthread_mutex_init(&info->joinMutex, NULL);
300 pthread_cond_init(&info->joinCond, NULL);
303 static void initThreadLocks(threadobject *);
305 static void *threadstartup(void *t)
307 threadobject *thread = t;
308 nativethread *info = &thread->info;
312 setthreadobject(thread);
314 pthread_mutex_lock(&threadlistlock);
315 info->prev = mainthreadobj;
316 info->next = tnext = mainthreadobj->info.next;
317 mainthreadobj->info.next = t;
318 tnext->info.prev = t;
319 pthread_mutex_unlock(&threadlistlock);
321 initThreadLocks(thread);
323 /* Find the run()V method and call it */
324 method = class_findmethod(thread->o.header.vftbl->class,
325 utf_new_char("run"), utf_new_char("()V"));
327 panic("Cannot find method \'void run ()\'");
329 asm_calljavafunction(method, thread, NULL, NULL, NULL);
331 if (info->_exceptionptr) {
332 utf_display((info->_exceptionptr)->vftbl->class->name);
336 freeLockRecordPools(thread->ee.lrpool);
338 pthread_mutex_lock(&threadlistlock);
339 info->next->info.prev = info->prev;
340 info->prev->info.next = info->next;
341 pthread_mutex_unlock(&threadlistlock);
343 pthread_mutex_lock(&info->joinMutex);
345 pthread_mutex_unlock(&info->joinMutex);
346 pthread_cond_broadcast(&info->joinCond);
351 void startThread(threadobject *t)
353 nativethread *info = &t->info;
354 pthread_create(&info->tid, NULL, threadstartup, t);
355 pthread_detach(info->tid);
358 void joinAllThreads()
360 pthread_mutex_lock(&threadlistlock);
361 while (mainthreadobj->info.prev != mainthreadobj) {
362 nativethread *info = &mainthreadobj->info.prev->info;
363 pthread_mutex_lock(&info->joinMutex);
364 pthread_mutex_unlock(&threadlistlock);
366 pthread_cond_wait(&info->joinCond, &info->joinMutex);
367 pthread_mutex_unlock(&info->joinMutex);
368 pthread_mutex_lock(&threadlistlock);
370 pthread_mutex_unlock(&threadlistlock);
373 bool aliveThread(java_lang_Thread *t)
375 return ((threadobject*) t)->info.tid != 0;
378 void sleepThread(s8 millis)
381 tv.tv_sec = millis / 1000;
382 tv.tv_nsec = millis % 1000 * 1000000;
383 do { } while (nanosleep(&tv, &tv) == EINTR);
391 static void timedCondWait(pthread_cond_t *cond, pthread_mutex_t *mutex, s8 millis)
394 struct timespec desttime;
395 gettimeofday(&now, NULL);
396 desttime.tv_sec = millis / 1000;
397 desttime.tv_nsec = millis % 1000 * 1000000;
398 pthread_cond_timedwait(cond, mutex, &desttime);
407 static void initExecutionEnvironment(ExecEnvironment *ee)
409 pthread_mutex_init(&ee->metaLockMutex, NULL);
410 pthread_cond_init(&ee->metaLockCond, NULL);
411 pthread_mutex_init(&ee->monitorLockMutex, NULL);
412 pthread_cond_init(&ee->monitorLockCond, NULL);
415 static void initLockRecord(monitorLockRecord *r, threadobject *t)
424 initThreadLocks(mainthreadobj);
427 static void initThreadLocks(threadobject *thread)
431 initExecutionEnvironment(&thread->ee);
432 for (i=0; i<INITIALLOCKRECORDS; i++) {
433 monitorLockRecord *r = &thread->ee.lr[i];
434 initLockRecord(r, thread);
435 r->nextFree = &thread->ee.lr[i+1];
437 thread->ee.lr[i-1].nextFree = NULL;
438 thread->ee.firstLR = &thread->ee.lr[0];
441 static inline int lockState(long r)
446 static inline void *lockRecord(long r)
448 return (void*) (r & ~3);
451 static inline long makeLockBits(void *r, long l)
453 return ((long) r) | l;
456 static lockRecordPool *allocLockRecordPool(threadobject *thread, int size)
458 lockRecordPool *p = mem_alloc(sizeof(lockRecordPoolHeader) + sizeof(monitorLockRecord) * size);
461 p->header.size = size;
462 for (i=0; i<size; i++) {
463 initLockRecord(&p->lr[i], thread);
464 p->lr[i].nextFree = &p->lr[i+1];
466 p->lr[i-1].nextFree = NULL;
470 static void freeLockRecordPools(lockRecordPool *pool)
473 lockRecordPool *n = pool->header.next;
474 mem_free(pool, sizeof(lockRecordPoolHeader) + sizeof(monitorLockRecord) * pool->header.size);
479 static monitorLockRecord *allocLockRecord(threadobject *t)
481 monitorLockRecord *r = t->ee.firstLR;
484 int poolsize = t->ee.lrpool ? t->ee.lrpool->header.size * 2 : INITIALLOCKRECORDS * 2;
485 lockRecordPool *pool = allocLockRecordPool(t, poolsize);
486 pool->header.next = t->ee.lrpool;
491 t->ee.firstLR = r->nextFree;
495 static void recycleLockRecord(threadobject *t, monitorLockRecord *r)
497 r->nextFree = t->ee.firstLR;
501 static monitorLockRecord *appendToQueue(monitorLockRecord *queue, monitorLockRecord *lr)
503 monitorLockRecord *queuestart = queue;
507 queue = queue->queue;
512 static monitorLockRecord *moveMyLRToFront(threadobject *t, monitorLockRecord *lr)
514 monitorLockRecord *pred = NULL;
515 monitorLockRecord *firstLR = lr;
516 while (lr->owner != t) {
522 pred->queue = lr->queue;
524 lr->storedBits = firstLR->storedBits;
528 static long getMetaLockSlow(threadobject *t, long predBits);
529 static void releaseMetaLockSlow(threadobject *t, long releaseBits);
531 static long getMetaLock(threadobject *t, java_objectheader *o)
533 long busyBits = makeLockBits(t, BUSY);
534 long lockBits = atomic_swap(&o->monitorBits, busyBits);
535 return lockState(lockBits) != BUSY ? lockBits : getMetaLockSlow(t, lockBits);
538 static long getMetaLockSlow(threadobject *t, long predBits)
541 threadobject *pred = lockRecord(predBits);
542 pthread_mutex_lock(&pred->ee.metaLockMutex);
543 if (!pred->ee.bitsForGrab) {
546 pthread_cond_wait(&pred->ee.metaLockCond, &pred->ee.metaLockMutex);
547 } while (!t->ee.gotMetaLockSlow);
548 t->ee.gotMetaLockSlow = false;
549 bits = t->ee.metaLockBits;
551 bits = pred->ee.metaLockBits;
552 pred->ee.bitsForGrab = false;
553 pthread_cond_signal(&pred->ee.metaLockCond);
555 pthread_mutex_unlock(&pred->ee.metaLockMutex);
559 static void releaseMetaLock(threadobject *t, java_objectheader *o, long releaseBits)
561 long busyBits = makeLockBits(t, BUSY);
562 long lockBits = compare_and_swap(&o->monitorBits, busyBits, releaseBits);
564 if (lockBits != busyBits)
565 releaseMetaLockSlow(t, releaseBits);
568 static void releaseMetaLockSlow(threadobject *t, long releaseBits)
570 pthread_mutex_lock(&t->ee.metaLockMutex);
572 assert(!t->ee.succ->ee.bitsForGrab);
573 assert(!t->ee.bitsForGrab);
574 assert(!t->ee.succ->ee.gotMetaLockSlow);
575 t->ee.succ->ee.metaLockBits = releaseBits;
576 t->ee.succ->ee.gotMetaLockSlow = true;
578 pthread_cond_signal(&t->ee.metaLockCond);
580 t->ee.metaLockBits = releaseBits;
581 t->ee.bitsForGrab = true;
583 pthread_cond_wait(&t->ee.metaLockCond, &t->ee.metaLockMutex);
584 } while (t->ee.bitsForGrab);
586 pthread_mutex_unlock(&t->ee.metaLockMutex);
589 static void monitorEnterSlow(threadobject *t, java_objectheader *o, long r);
591 void monitorEnter(threadobject *t, java_objectheader *o)
593 long r = getMetaLock(t, o);
594 int state = lockState(r);
596 if (state == NEUTRAL) {
597 monitorLockRecord *lr = allocLockRecord(t);
599 releaseMetaLock(t, o, makeLockBits(lr, LOCKED));
600 } else if (state == LOCKED) {
601 monitorLockRecord *ownerLR = lockRecord(r);
602 if (ownerLR->owner == t) {
603 ownerLR->lockCount++;
604 releaseMetaLock(t, o, r);
606 monitorLockRecord *lr = allocLockRecord(t);
607 ownerLR->queue = appendToQueue(ownerLR->queue, lr);
608 monitorEnterSlow(t, o, r);
610 } else if (state == WAITERS) {
611 monitorLockRecord *lr = allocLockRecord(t);
612 monitorLockRecord *firstWaiterLR = lockRecord(r);
613 lr->queue = firstWaiterLR;
614 lr->storedBits = firstWaiterLR->storedBits;
615 releaseMetaLock(t, o, makeLockBits(lr, LOCKED));
619 static void monitorEnterSlow(threadobject *t, java_objectheader *o, long r)
621 monitorLockRecord *lr;
622 monitorLockRecord *firstWaiterLR;
623 while (lockState(r) == LOCKED) {
624 pthread_mutex_lock(&t->ee.monitorLockMutex);
625 releaseMetaLock(t, o, r);
626 pthread_cond_wait(&t->ee.monitorLockCond, &t->ee.monitorLockMutex);
627 pthread_mutex_unlock(&t->ee.monitorLockMutex);
628 r = getMetaLock(t, o);
630 assert(lockState(r) == WAITERS);
631 lr = moveMyLRToFront(t, lockRecord(r));
632 releaseMetaLock(t, o, makeLockBits(lr, LOCKED));
635 static void monitorExitSlow(threadobject *t, java_objectheader *o, monitorLockRecord *lr);
637 void monitorExit(threadobject *t, java_objectheader *o)
639 long r = getMetaLock(t, o);
640 monitorLockRecord *ownerLR = lockRecord(r);
641 int state = lockState(r);
642 if (state == LOCKED && ownerLR->owner == t) {
643 assert(ownerLR->lockCount >= 1);
644 if (ownerLR->lockCount == 1) {
645 if (ownerLR->queue == NULL) {
646 assert(lockState(ownerLR->storedBits) == NEUTRAL);
647 releaseMetaLock(t, o, ownerLR->storedBits);
649 ownerLR->queue->storedBits = ownerLR->storedBits;
650 monitorExitSlow(t, o, ownerLR->queue);
651 ownerLR->queue = NULL;
653 recycleLockRecord(t, ownerLR);
655 ownerLR->lockCount--;
656 releaseMetaLock(t, o, r);
659 releaseMetaLock(t, o, r);
660 panic("Illegal monitor exception");
664 static threadobject *wakeupEE(monitorLockRecord *lr)
666 while (lr->queue && lr->queue->owner->ee.isWaitingForNotify)
671 static void monitorExitSlow(threadobject *t, java_objectheader *o, monitorLockRecord *lr)
673 threadobject *wakeEE = wakeupEE(lr);
675 pthread_mutex_lock(&wakeEE->ee.monitorLockMutex);
676 releaseMetaLock(t, o, makeLockBits(lr, WAITERS));
677 pthread_cond_signal(&wakeEE->ee.monitorLockCond);
678 pthread_mutex_unlock(&wakeEE->ee.monitorLockMutex);
680 releaseMetaLock(t, o, makeLockBits(lr, WAITERS));
684 void monitorWait(threadobject *t, java_objectheader *o, s8 millis)
686 long r = getMetaLock(t, o);
687 monitorLockRecord *ownerLR = lockRecord(r);
688 int state = lockState(r);
689 if (state == LOCKED && ownerLR->owner == t) {
690 pthread_mutex_lock(&t->ee.monitorLockMutex);
691 t->ee.isWaitingForNotify = true;
692 monitorExitSlow(t, o, ownerLR);
694 pthread_cond_wait(&t->ee.monitorLockCond, &t->ee.monitorLockMutex);
696 timedCondWait(&t->ee.monitorLockCond, &t->ee.monitorLockMutex, millis);
697 t->ee.isWaitingForNotify = false;
698 pthread_mutex_unlock(&t->ee.monitorLockMutex);
699 r = getMetaLock(t, o);
700 monitorEnterSlow(t, o, r);
702 releaseMetaLock(t, o, r);
703 panic("Illegal monitor exception");
707 static void notifyOneOrAll(threadobject *t, java_objectheader *o, bool one)
709 long r = getMetaLock(t, o);
710 monitorLockRecord *ownerLR = lockRecord(r);
711 int state = lockState(r);
712 if (state == LOCKED && ownerLR->owner == t) {
713 monitorLockRecord *q = ownerLR->queue;
715 if (q->owner->ee.isWaitingForNotify) {
716 q->owner->ee.isWaitingForNotify = false;
722 releaseMetaLock(t, o, r);
724 releaseMetaLock(t, o, r);
725 panic("Illegal monitor exception");
729 void wait_cond_for_object(java_objectheader *o, s8 time)
731 threadobject *t = (threadobject*) THREADOBJECT;
732 monitorWait(t, o, time);
735 void signal_cond_for_object(java_objectheader *o)
737 threadobject *t = (threadobject*) THREADOBJECT;
738 notifyOneOrAll(t, o, true);
741 void broadcast_cond_for_object(java_objectheader *o)
743 threadobject *t = (threadobject*) THREADOBJECT;
744 notifyOneOrAll(t, o, false);