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;
54 static pthread_mutex_t cast_mutex = PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP;
55 static pthread_mutex_t compiler_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
61 pthread_mutex_lock(&cast_mutex);
66 pthread_mutex_unlock(&cast_mutex);
71 pthread_mutex_lock(&compiler_mutex);
74 void compiler_unlock()
76 pthread_mutex_unlock(&compiler_mutex);
81 static int criticalcompare(const void *pa, const void *pb, void *param)
83 const threadcritnode *na = pa;
84 const threadcritnode *nb = pb;
86 if (na->mcodebegin < nb->mcodebegin)
88 if (na->mcodebegin > nb->mcodebegin)
93 static const threadcritnode *findcritical(u1 *mcodeptr)
95 struct avl_node *n = criticaltree->avl_root;
96 const threadcritnode *m = NULL;
101 const threadcritnode *d = n->avl_data;
102 if (mcodeptr == d->mcodebegin)
104 if (mcodeptr < d->mcodebegin) {
110 if (n->avl_link[1]) {
119 void thread_registercritical(threadcritnode *n)
121 avl_insert(criticaltree, n);
124 static u1 *thread_checkcritical(u1 *mcodeptr)
126 const threadcritnode *n = findcritical(mcodeptr);
127 return (n && mcodeptr < n->mcodeend) ? n->mcodebegin : NULL;
130 static pthread_mutex_t stopworldlock = PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP;
131 volatile int stopworldwhere;
134 * where - 1 from within GC
137 void lock_stopworld(int where)
139 pthread_mutex_lock(&stopworldlock);
140 stopworldwhere = where;
143 void unlock_stopworld()
146 pthread_mutex_unlock(&stopworldlock);
149 static sem_t suspend_ack;
151 static void sigsuspend_handler(struct sigcontext *ctx)
158 if ((critical = thread_checkcritical((void*) ctx->eip)) != NULL)
159 ctx->eip = (long) critical;
162 sem_post(&suspend_ack);
166 sigdelset(&sigs, sig);
170 int cacao_suspendhandler(struct sigcontext *ctx)
172 if (stopworldwhere != 2)
175 sigsuspend_handler(ctx);
179 static void setthreadobject(threadobject *thread)
181 #if !defined(HAVE___THREAD)
182 pthread_setspecific(tkey_threadinfo, thread);
189 * Initialize threads.
195 // int sig1 = GC_signum1(), sig2 = GC_signum2();
197 /* Allocate something so the garbage collector's signal handlers are */
199 heap_allocate(1, false, NULL);
201 mainthreadobj = NEW(threadobject);
202 memset(mainthreadobj, 0, sizeof(threadobject));
203 #if !defined(HAVE___THREAD)
204 pthread_key_create(&tkey_threadinfo, NULL);
206 setthreadobject(mainthreadobj);
208 criticaltree = avl_create(criticalcompare, NULL, NULL);
211 static void freeLockRecordPools(lockRecordPool *);
214 initThreads(u1 *stackbottom)
216 classinfo *threadclass;
217 java_lang_Thread *mainthread;
218 threadobject *tempthread = mainthreadobj;
222 threadclass = loader_load_sysclass(NULL,utf_new_char("java/lang/Thread"));
224 freeLockRecordPools(mainthreadobj->ee.lrpool);
225 threadclass->instancesize = sizeof(threadobject);
226 mainthreadobj = (threadobject*) builtin_new(threadclass);
227 assert(mainthreadobj);
228 FREE(tempthread, threadobject);
229 initThread(&mainthreadobj->o);
231 #if !defined(HAVE___THREAD)
232 pthread_setspecific(tkey_threadinfo, mainthreadobj);
234 threadobj = mainthreadobj;
237 mainthread = &mainthreadobj->o;
239 mainthreadobj->info.next = mainthreadobj;
240 mainthreadobj->info.prev = mainthreadobj;
242 mainthread->name=javastring_new(utf_new_char("main"));
244 /* Allocate and init ThreadGroup */
245 mainthread->group = (java_lang_ThreadGroup*)native_new_and_init(loader_load(utf_new_char("java/lang/ThreadGroup")));
246 assert(mainthread->group != 0);
249 void initThread(java_lang_Thread *t)
251 nativethread *info = &((threadobject*) t)->info;
252 pthread_mutex_init(&info->joinMutex, NULL);
253 pthread_cond_init(&info->joinCond, NULL);
256 static pthread_mutex_t threadlistlock = PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP;
258 static void initThreadLocks(threadobject *);
260 static void *threadstartup(void *t)
262 threadobject *thread = t;
263 nativethread *info = &thread->info;
267 setthreadobject(thread);
269 pthread_mutex_lock(&threadlistlock);
270 info->prev = mainthreadobj;
271 info->next = tnext = mainthreadobj->info.next;
272 mainthreadobj->info.next = t;
273 tnext->info.prev = t;
274 pthread_mutex_unlock(&threadlistlock);
276 initThreadLocks(thread);
278 /* Find the run()V method and call it */
279 method = class_findmethod(thread->o.header.vftbl->class,
280 utf_new_char("run"), utf_new_char("()V"));
282 panic("Cannot find method \'void run ()\'");
284 asm_calljavafunction(method, thread, NULL, NULL, NULL);
286 if (info->_exceptionptr) {
287 utf_display((info->_exceptionptr)->vftbl->class->name);
291 freeLockRecordPools(thread->ee.lrpool);
293 pthread_mutex_lock(&threadlistlock);
294 info->next->info.prev = info->prev;
295 info->prev->info.next = info->next;
296 pthread_mutex_unlock(&threadlistlock);
298 pthread_mutex_lock(&info->joinMutex);
300 pthread_mutex_unlock(&info->joinMutex);
301 pthread_cond_broadcast(&info->joinCond);
306 void startThread(threadobject *t)
308 nativethread *info = &t->info;
309 pthread_create(&info->tid, NULL, threadstartup, t);
310 pthread_detach(info->tid);
313 void joinAllThreads()
315 pthread_mutex_lock(&threadlistlock);
316 while (mainthreadobj->info.prev != mainthreadobj) {
317 nativethread *info = &mainthreadobj->info.prev->info;
318 pthread_mutex_lock(&info->joinMutex);
319 pthread_mutex_unlock(&threadlistlock);
321 pthread_cond_wait(&info->joinCond, &info->joinMutex);
322 pthread_mutex_unlock(&info->joinMutex);
323 pthread_mutex_lock(&threadlistlock);
325 pthread_mutex_unlock(&threadlistlock);
328 bool aliveThread(java_lang_Thread *t)
330 return ((threadobject*) t)->info.tid != 0;
333 void sleepThread(s8 millis)
336 tv.tv_sec = millis / 1000;
337 tv.tv_nsec = millis % 1000 * 1000000;
338 do { } while (nanosleep(&tv, &tv) == EINTR);
346 static void timedCondWait(pthread_cond_t *cond, pthread_mutex_t *mutex, s8 millis)
349 struct timespec desttime;
350 gettimeofday(&now, NULL);
351 desttime.tv_sec = millis / 1000;
352 desttime.tv_nsec = millis % 1000 * 1000000;
353 pthread_cond_timedwait(cond, mutex, &desttime);
362 static void initExecutionEnvironment(ExecEnvironment *ee)
364 pthread_mutex_init(&ee->metaLockMutex, NULL);
365 pthread_cond_init(&ee->metaLockCond, NULL);
366 pthread_mutex_init(&ee->monitorLockMutex, NULL);
367 pthread_cond_init(&ee->monitorLockCond, NULL);
370 static void initLockRecord(monitorLockRecord *r, threadobject *t)
379 initThreadLocks(mainthreadobj);
382 static void initThreadLocks(threadobject *thread)
386 initExecutionEnvironment(&thread->ee);
387 for (i=0; i<INITIALLOCKRECORDS; i++) {
388 monitorLockRecord *r = &thread->ee.lr[i];
389 initLockRecord(r, thread);
390 r->nextFree = &thread->ee.lr[i+1];
392 thread->ee.lr[i-1].nextFree = NULL;
393 thread->ee.firstLR = &thread->ee.lr[0];
396 static inline int lockState(long r)
401 static inline void *lockRecord(long r)
403 return (void*) (r & ~3);
406 static inline long makeLockBits(void *r, long l)
408 return ((long) r) | l;
411 static lockRecordPool *allocLockRecordPool(threadobject *thread, int size)
413 lockRecordPool *p = mem_alloc(sizeof(lockRecordPoolHeader) + sizeof(monitorLockRecord) * size);
416 p->header.size = size;
417 for (i=0; i<size; i++) {
418 initLockRecord(&p->lr[i], thread);
419 p->lr[i].nextFree = &p->lr[i+1];
421 p->lr[i-1].nextFree = NULL;
425 static void freeLockRecordPools(lockRecordPool *pool)
428 lockRecordPool *n = pool->header.next;
429 mem_free(pool, sizeof(lockRecordPoolHeader) + sizeof(monitorLockRecord) * pool->header.size);
434 static monitorLockRecord *allocLockRecord(threadobject *t)
436 monitorLockRecord *r = t->ee.firstLR;
439 int poolsize = t->ee.lrpool ? t->ee.lrpool->header.size * 2 : INITIALLOCKRECORDS * 2;
440 lockRecordPool *pool = allocLockRecordPool(t, poolsize);
441 pool->header.next = t->ee.lrpool;
446 t->ee.firstLR = r->nextFree;
450 static void recycleLockRecord(threadobject *t, monitorLockRecord *r)
452 r->nextFree = t->ee.firstLR;
456 static monitorLockRecord *appendToQueue(monitorLockRecord *queue, monitorLockRecord *lr)
458 monitorLockRecord *queuestart = queue;
462 queue = queue->queue;
467 static monitorLockRecord *moveMyLRToFront(threadobject *t, monitorLockRecord *lr)
469 monitorLockRecord *pred = NULL;
470 monitorLockRecord *firstLR = lr;
471 while (lr->owner != t) {
477 pred->queue = lr->queue;
479 lr->storedBits = firstLR->storedBits;
483 static long getMetaLockSlow(threadobject *t, long predBits);
484 static void releaseMetaLockSlow(threadobject *t, long releaseBits);
486 static long getMetaLock(threadobject *t, java_objectheader *o)
488 long busyBits = makeLockBits(t, BUSY);
489 long lockBits = atomic_swap(&o->monitorBits, busyBits);
490 return lockState(lockBits) != BUSY ? lockBits : getMetaLockSlow(t, lockBits);
493 static long getMetaLockSlow(threadobject *t, long predBits)
496 threadobject *pred = lockRecord(predBits);
497 pthread_mutex_lock(&pred->ee.metaLockMutex);
498 if (!pred->ee.bitsForGrab) {
501 pthread_cond_wait(&pred->ee.metaLockCond, &pred->ee.metaLockMutex);
502 } while (!t->ee.gotMetaLockSlow);
503 t->ee.gotMetaLockSlow = false;
504 bits = t->ee.metaLockBits;
506 bits = pred->ee.metaLockBits;
507 pred->ee.bitsForGrab = false;
508 pthread_cond_signal(&pred->ee.metaLockCond);
510 pthread_mutex_unlock(&pred->ee.metaLockMutex);
514 static void releaseMetaLock(threadobject *t, java_objectheader *o, long releaseBits)
516 long busyBits = makeLockBits(t, BUSY);
517 long lockBits = compare_and_swap(&o->monitorBits, busyBits, releaseBits);
519 if (lockBits != busyBits)
520 releaseMetaLockSlow(t, releaseBits);
523 static void releaseMetaLockSlow(threadobject *t, long releaseBits)
525 pthread_mutex_lock(&t->ee.metaLockMutex);
527 assert(!t->ee.succ->ee.bitsForGrab);
528 assert(!t->ee.bitsForGrab);
529 assert(!t->ee.succ->ee.gotMetaLockSlow);
530 t->ee.succ->ee.metaLockBits = releaseBits;
531 t->ee.succ->ee.gotMetaLockSlow = true;
533 pthread_cond_signal(&t->ee.metaLockCond);
535 t->ee.metaLockBits = releaseBits;
536 t->ee.bitsForGrab = true;
538 pthread_cond_wait(&t->ee.metaLockCond, &t->ee.metaLockMutex);
539 } while (t->ee.bitsForGrab);
541 pthread_mutex_unlock(&t->ee.metaLockMutex);
544 static void monitorEnterSlow(threadobject *t, java_objectheader *o, long r);
546 void monitorEnter(threadobject *t, java_objectheader *o)
548 long r = getMetaLock(t, o);
549 int state = lockState(r);
551 if (state == NEUTRAL) {
552 monitorLockRecord *lr = allocLockRecord(t);
554 releaseMetaLock(t, o, makeLockBits(lr, LOCKED));
555 } else if (state == LOCKED) {
556 monitorLockRecord *ownerLR = lockRecord(r);
557 if (ownerLR->owner == t) {
558 ownerLR->lockCount++;
559 releaseMetaLock(t, o, r);
561 monitorLockRecord *lr = allocLockRecord(t);
562 ownerLR->queue = appendToQueue(ownerLR->queue, lr);
563 monitorEnterSlow(t, o, r);
565 } else if (state == WAITERS) {
566 monitorLockRecord *lr = allocLockRecord(t);
567 monitorLockRecord *firstWaiterLR = lockRecord(r);
568 lr->queue = firstWaiterLR;
569 lr->storedBits = firstWaiterLR->storedBits;
570 releaseMetaLock(t, o, makeLockBits(lr, LOCKED));
574 static void monitorEnterSlow(threadobject *t, java_objectheader *o, long r)
576 monitorLockRecord *lr;
577 monitorLockRecord *firstWaiterLR;
578 while (lockState(r) == LOCKED) {
579 pthread_mutex_lock(&t->ee.monitorLockMutex);
580 releaseMetaLock(t, o, r);
581 pthread_cond_wait(&t->ee.monitorLockCond, &t->ee.monitorLockMutex);
582 pthread_mutex_unlock(&t->ee.monitorLockMutex);
583 r = getMetaLock(t, o);
585 assert(lockState(r) == WAITERS);
586 lr = moveMyLRToFront(t, lockRecord(r));
587 releaseMetaLock(t, o, makeLockBits(lr, LOCKED));
590 static void monitorExitSlow(threadobject *t, java_objectheader *o, monitorLockRecord *lr);
592 void monitorExit(threadobject *t, java_objectheader *o)
594 long r = getMetaLock(t, o);
595 monitorLockRecord *ownerLR = lockRecord(r);
596 int state = lockState(r);
597 if (state == LOCKED && ownerLR->owner == t) {
598 assert(ownerLR->lockCount >= 1);
599 if (ownerLR->lockCount == 1) {
600 if (ownerLR->queue == NULL) {
601 assert(lockState(ownerLR->storedBits) == NEUTRAL);
602 releaseMetaLock(t, o, ownerLR->storedBits);
604 ownerLR->queue->storedBits = ownerLR->storedBits;
605 monitorExitSlow(t, o, ownerLR->queue);
606 ownerLR->queue = NULL;
608 recycleLockRecord(t, ownerLR);
610 ownerLR->lockCount--;
611 releaseMetaLock(t, o, r);
614 releaseMetaLock(t, o, r);
615 panic("Illegal monitor exception");
619 static threadobject *wakeupEE(monitorLockRecord *lr)
621 while (lr->queue && lr->queue->owner->ee.isWaitingForNotify)
626 static void monitorExitSlow(threadobject *t, java_objectheader *o, monitorLockRecord *lr)
628 threadobject *wakeEE = wakeupEE(lr);
630 pthread_mutex_lock(&wakeEE->ee.monitorLockMutex);
631 releaseMetaLock(t, o, makeLockBits(lr, WAITERS));
632 pthread_cond_signal(&wakeEE->ee.monitorLockCond);
633 pthread_mutex_unlock(&wakeEE->ee.monitorLockMutex);
635 releaseMetaLock(t, o, makeLockBits(lr, WAITERS));
639 void monitorWait(threadobject *t, java_objectheader *o, s8 millis)
641 long r = getMetaLock(t, o);
642 monitorLockRecord *ownerLR = lockRecord(r);
643 int state = lockState(r);
644 if (state == LOCKED && ownerLR->owner == t) {
645 pthread_mutex_lock(&t->ee.monitorLockMutex);
646 t->ee.isWaitingForNotify = true;
647 monitorExitSlow(t, o, ownerLR);
649 pthread_cond_wait(&t->ee.monitorLockCond, &t->ee.monitorLockMutex);
651 timedCondWait(&t->ee.monitorLockCond, &t->ee.monitorLockMutex, millis);
652 t->ee.isWaitingForNotify = false;
653 pthread_mutex_unlock(&t->ee.monitorLockMutex);
654 r = getMetaLock(t, o);
655 monitorEnterSlow(t, o, r);
657 releaseMetaLock(t, o, r);
658 panic("Illegal monitor exception");
662 static void notifyOneOrAll(threadobject *t, java_objectheader *o, bool one)
664 long r = getMetaLock(t, o);
665 monitorLockRecord *ownerLR = lockRecord(r);
666 int state = lockState(r);
667 if (state == LOCKED && ownerLR->owner == t) {
668 monitorLockRecord *q = ownerLR->queue;
670 if (q->owner->ee.isWaitingForNotify) {
671 q->owner->ee.isWaitingForNotify = false;
677 releaseMetaLock(t, o, r);
679 releaseMetaLock(t, o, r);
680 panic("Illegal monitor exception");
684 void wait_cond_for_object(java_objectheader *o, s8 time)
686 threadobject *t = (threadobject*) THREADOBJECT;
687 monitorWait(t, o, time);
690 void signal_cond_for_object(java_objectheader *o)
692 threadobject *t = (threadobject*) THREADOBJECT;
693 notifyOneOrAll(t, o, true);
696 void broadcast_cond_for_object(java_objectheader *o)
698 threadobject *t = (threadobject*) THREADOBJECT;
699 notifyOneOrAll(t, o, false);