1 /* src/threads/native/threads.c - native threads support
3 Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
4 C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
5 E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
6 J. Wenninger, Institut f. Computersprachen - TU Wien
8 This file is part of CACAO.
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License as
12 published by the Free Software Foundation; either version 2, or (at
13 your option) any later version.
15 This program is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25 Contact: cacao@cacaojvm.org
29 Changes: Christian Thalinger
32 $Id: threads.c 4865 2006-05-01 12:40:18Z edwin $
42 #include <sys/types.h>
50 #include <semaphore.h>
56 #ifndef USE_MD_THREAD_STUFF
57 #include "machine-instr.h"
59 #include "threads/native/generic-primitives.h"
63 #include "mm/memory.h"
64 #include "native/native.h"
65 #include "native/include/java_lang_Object.h"
66 #include "native/include/java_lang_Throwable.h"
67 #include "native/include/java_lang_Thread.h"
68 #include "native/include/java_lang_ThreadGroup.h"
69 #include "native/include/java_lang_VMThread.h"
70 #include "threads/native/threads.h"
71 #include "toolbox/avl.h"
72 #include "toolbox/logging.h"
73 #include "vm/builtin.h"
74 #include "vm/exceptions.h"
75 #include "vm/global.h"
76 #include "vm/loader.h"
77 #include "vm/options.h"
78 #include "vm/stringlocal.h"
80 #include "vm/jit/asmpart.h"
82 #if !defined(__DARWIN__)
83 #if defined(__LINUX__)
84 #define GC_LINUX_THREADS
85 #elif defined(__MIPS__)
86 #define GC_IRIX_THREADS
88 #include "boehm-gc/include/gc.h"
91 #ifdef USE_MD_THREAD_STUFF
92 pthread_mutex_t _atomic_add_lock = PTHREAD_MUTEX_INITIALIZER;
93 pthread_mutex_t _cas_lock = PTHREAD_MUTEX_INITIALIZER;
94 pthread_mutex_t _mb_lock = PTHREAD_MUTEX_INITIALIZER;
99 /* We need this for older MacOSX (10.1.x) */
102 pthread_mutex_t mutex;
105 } pthread_mutex_rec_t;
107 static void pthread_mutex_init_rec(pthread_mutex_rec_t *m)
109 pthread_mutex_init(&m->mutex, NULL);
113 static void pthread_mutex_destroy_rec(pthread_mutex_rec_t *m)
115 pthread_mutex_destroy(&m->mutex);
118 static void pthread_mutex_lock_rec(pthread_mutex_rec_t *m)
123 pthread_mutex_lock(&m->mutex);
124 m->owner = pthread_self();
129 if (m->owner != pthread_self()) {
130 pthread_mutex_lock(&m->mutex);
140 static void pthread_mutex_unlock_rec(pthread_mutex_rec_t *m)
143 pthread_mutex_unlock(&m->mutex);
148 #define pthread_mutex_lock_rec pthread_mutex_lock
149 #define pthread_mutex_unlock_rec pthread_mutex_unlock
150 #define pthread_mutex_rec_t pthread_mutex_t
152 #endif /* MUTEXSIM */
154 /* threads_sem_wait ************************************************************
156 Wait for a semaphore, non-interruptible.
158 IMPORTANT: Always use this function instead of `sem_wait` directly, as
159 `sem_wait` may be interrupted by signals!
162 sem..............the semaphore to wait on
164 *******************************************************************************/
166 void threads_sem_wait(sem_t *sem)
174 } while (errno == EINTR);
176 fprintf(stderr,"error: sem_wait returned unexpected error %d: %s\n",
177 errno, strerror(errno));
181 static void setPriority(pthread_t tid, int priority)
183 struct sched_param schedp;
186 pthread_getschedparam(tid, &policy, &schedp);
187 schedp.sched_priority = priority;
188 pthread_setschedparam(tid, policy, &schedp);
192 static avl_tree *criticaltree;
193 threadobject *mainthreadobj;
195 #ifndef HAVE___THREAD
196 pthread_key_t tkey_threadinfo;
198 __thread threadobject *threadobj;
201 static pthread_mutex_rec_t compiler_mutex;
205 pthread_mutex_lock_rec(&compiler_mutex);
208 void compiler_unlock()
210 pthread_mutex_unlock_rec(&compiler_mutex);
213 static s4 criticalcompare(const void *pa, const void *pb)
215 const threadcritnode *na = pa;
216 const threadcritnode *nb = pb;
218 if (na->mcodebegin < nb->mcodebegin)
220 if (na->mcodebegin > nb->mcodebegin)
226 static const threadcritnode *findcritical(u1 *mcodeptr)
229 const threadcritnode *m;
231 n = criticaltree->root;
238 const threadcritnode *d = n->data;
240 if (mcodeptr == d->mcodebegin)
243 if (mcodeptr < d->mcodebegin) {
264 void thread_registercritical(threadcritnode *n)
266 avl_insert(criticaltree, n);
269 u1 *thread_checkcritical(u1 *mcodeptr)
271 const threadcritnode *n = findcritical(mcodeptr);
272 return (n && mcodeptr < n->mcodeend && mcodeptr > n->mcodebegin) ? n->mcoderestart : NULL;
275 static void thread_addstaticcritical()
277 /* XXX TWISTI: this is just a quick hack */
278 #if defined(ENABLE_JIT)
279 threadcritnode *n = &asm_criticalsections;
281 while (n->mcodebegin)
282 thread_registercritical(n++);
286 static pthread_mutex_t threadlistlock;
288 static pthread_mutex_t stopworldlock;
289 volatile int stopworldwhere;
291 static sem_t suspend_ack;
292 #if defined(__MIPS__)
293 static pthread_mutex_t suspend_ack_lock = PTHREAD_MUTEX_INITIALIZER;
294 static pthread_cond_t suspend_cond = PTHREAD_COND_INITIALIZER;
298 * where - 1 from within GC
301 void lock_stopworld(int where)
303 pthread_mutex_lock(&stopworldlock);
304 stopworldwhere = where;
307 void unlock_stopworld()
310 pthread_mutex_unlock(&stopworldlock);
313 #if !defined(__DARWIN__)
314 /* Caller must hold threadlistlock */
315 static int cast_sendsignals(int sig, int count)
318 threadobject *tobj = mainthreadobj;
319 nativethread *infoself = THREADINFO;
324 tobj = tobj->info.next;
325 } while (tobj != mainthreadobj);
329 nativethread *info = &tobj->info;
330 if (info != infoself)
331 pthread_kill(info->tid, sig);
332 tobj = tobj->info.next;
333 } while (tobj != mainthreadobj);
340 static void cast_darwinstop()
342 threadobject *tobj = mainthreadobj;
343 nativethread *infoself = THREADINFO;
346 nativethread *info = &tobj->info;
347 if (info != infoself)
349 thread_state_flavor_t flavor = PPC_THREAD_STATE;
350 mach_msg_type_number_t thread_state_count = PPC_THREAD_STATE_COUNT;
351 ppc_thread_state_t thread_state;
352 mach_port_t thread = info->mach_thread;
355 r = thread_suspend(thread);
356 if (r != KERN_SUCCESS) {
357 log_text("thread_suspend failed");
361 r = thread_get_state(thread, flavor,
362 (natural_t*)&thread_state, &thread_state_count);
363 if (r != KERN_SUCCESS) {
364 log_text("thread_get_state failed");
368 thread_restartcriticalsection(&thread_state);
370 r = thread_set_state(thread, flavor,
371 (natural_t*)&thread_state, thread_state_count);
372 if (r != KERN_SUCCESS) {
373 log_text("thread_set_state failed");
377 tobj = tobj->info.next;
378 } while (tobj != mainthreadobj);
381 static void cast_darwinresume()
383 threadobject *tobj = mainthreadobj;
384 nativethread *infoself = THREADINFO;
387 nativethread *info = &tobj->info;
388 if (info != infoself)
390 mach_port_t thread = info->mach_thread;
393 r = thread_resume(thread);
394 if (r != KERN_SUCCESS) {
395 log_text("thread_resume failed");
399 tobj = tobj->info.next;
400 } while (tobj != mainthreadobj);
405 #if defined(__MIPS__)
406 static void cast_irixresume()
408 pthread_mutex_lock(&suspend_ack_lock);
409 pthread_cond_broadcast(&suspend_cond);
410 pthread_mutex_unlock(&suspend_ack_lock);
414 void cast_stopworld()
418 pthread_mutex_lock(&threadlistlock);
419 #if defined(__DARWIN__)
422 count = cast_sendsignals(GC_signum1(), 0);
423 for (i=0; i<count; i++)
424 threads_sem_wait(&suspend_ack);
426 pthread_mutex_unlock(&threadlistlock);
429 void cast_startworld()
431 pthread_mutex_lock(&threadlistlock);
432 #if defined(__DARWIN__)
434 #elif defined(__MIPS__)
437 cast_sendsignals(GC_signum2(), -1);
439 pthread_mutex_unlock(&threadlistlock);
443 #if !defined(__DARWIN__)
444 static void sigsuspend_handler(ucontext_t *ctx)
449 /* XXX TWISTI: this is just a quick hack */
450 #if defined(ENABLE_JIT)
451 thread_restartcriticalsection(ctx);
454 /* Do as Boehm does. On IRIX a condition variable is used for wake-up
455 (not POSIX async-safe). */
456 #if defined(__IRIX__)
457 pthread_mutex_lock(&suspend_ack_lock);
458 sem_post(&suspend_ack);
459 pthread_cond_wait(&suspend_cond, &suspend_ack_lock);
460 pthread_mutex_unlock(&suspend_ack_lock);
462 sem_post(&suspend_ack);
466 sigdelset(&sigs, sig);
471 int cacao_suspendhandler(ucontext_t *ctx)
473 if (stopworldwhere != 2)
476 sigsuspend_handler(ctx);
481 #if !defined(ENABLE_JVMTI)
482 static void setthreadobject(threadobject *thread)
484 void setthreadobject(threadobject *thread)
487 #if !defined(HAVE___THREAD)
488 pthread_setspecific(tkey_threadinfo, thread);
495 /* thread_setself **************************************************************
499 *******************************************************************************/
501 void *thread_getself(void)
507 static monitorLockRecord *dummyLR;
509 static void initPools();
512 /* thread_preinit **************************************************************
514 Do some early initialization of stuff required.
516 *******************************************************************************/
518 void threads_preinit(void)
521 pthread_mutexattr_t mutexattr;
522 pthread_mutexattr_init(&mutexattr);
523 pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_RECURSIVE);
524 pthread_mutex_init(&compiler_mutex, &mutexattr);
525 pthread_mutexattr_destroy(&mutexattr);
527 pthread_mutex_init_rec(&compiler_mutex);
530 pthread_mutex_init(&threadlistlock, NULL);
531 pthread_mutex_init(&stopworldlock, NULL);
533 /* Allocate something so the garbage collector's signal handlers
535 heap_allocate(1, false, NULL);
537 mainthreadobj = NEW(threadobject);
538 mainthreadobj->info.tid = pthread_self();
539 #if !defined(HAVE___THREAD)
540 pthread_key_create(&tkey_threadinfo, NULL);
542 setthreadobject(mainthreadobj);
545 /* Every newly created object's monitorPtr points here so we save
546 a check against NULL */
548 dummyLR = NEW(monitorLockRecord);
550 dummyLR->ownerThread = NULL;
551 dummyLR->waiting = NULL;
552 dummyLR->incharge = dummyLR;
554 /* we need a working dummyLR before initializing the critical
557 criticaltree = avl_create(&criticalcompare);
559 thread_addstaticcritical();
560 sem_init(&suspend_ack, 0, 0);
564 static pthread_attr_t threadattr;
566 static void freeLockRecordPools(lockRecordPool *);
569 /* threads_init ****************************************************************
571 Initializes the threads required by the JVM: main, finalizer.
573 *******************************************************************************/
575 bool threads_init(u1 *stackbottom)
577 java_lang_String *threadname;
578 java_lang_Thread *mainthread;
579 java_lang_ThreadGroup *threadgroup;
580 threadobject *tempthread;
583 tempthread = mainthreadobj;
585 freeLockRecordPools(mainthreadobj->ee.lrpool);
587 /* This is kinda tricky, we grow the java.lang.Thread object so we
588 can keep the execution environment there. No Thread object must
589 have been created at an earlier time. */
591 class_java_lang_VMThread->instancesize = sizeof(threadobject);
593 /* create a VMThread */
595 mainthreadobj = (threadobject *) builtin_new(class_java_lang_VMThread);
600 FREE(tempthread, threadobject);
602 initThread(&mainthreadobj->o);
604 setthreadobject(mainthreadobj);
608 mainthreadobj->info.next = mainthreadobj;
609 mainthreadobj->info.prev = mainthreadobj;
611 #if defined(ENABLE_INTRP)
612 /* create interpreter stack */
615 MSET(intrp_main_stack, 0, u1, opt_stacksize);
616 mainthreadobj->info._global_sp = intrp_main_stack + opt_stacksize;
620 threadname = javastring_new(utf_new_char("main"));
622 /* allocate and init ThreadGroup */
624 threadgroup = (java_lang_ThreadGroup *)
625 native_new_and_init(class_java_lang_ThreadGroup);
628 throw_exception_exit();
630 /* create a Thread */
632 mainthread = (java_lang_Thread *) builtin_new(class_java_lang_Thread);
635 throw_exception_exit();
637 mainthreadobj->o.thread = mainthread;
639 /* call Thread.<init>(Ljava/lang/VMThread;Ljava/lang/String;IZ)V */
641 method = class_resolveclassmethod(class_java_lang_Thread,
643 utf_new_char("(Ljava/lang/VMThread;Ljava/lang/String;IZ)V"),
644 class_java_lang_Thread,
650 (void) vm_call_method(method, (java_objectheader *) mainthread,
651 mainthreadobj, threadname, 5, false);
656 mainthread->group = threadgroup;
658 /* add mainthread to ThreadGroup */
660 method = class_resolveclassmethod(class_java_lang_ThreadGroup,
661 utf_new_char("addThread"),
662 utf_new_char("(Ljava/lang/Thread;)V"),
663 class_java_lang_ThreadGroup,
669 (void) vm_call_method(method, (java_objectheader *) threadgroup,
675 setPriority(pthread_self(), 5);
677 pthread_attr_init(&threadattr);
678 pthread_attr_setdetachstate(&threadattr, PTHREAD_CREATE_DETACHED);
680 /* everything's ok */
686 void initThread(java_lang_VMThread *t)
688 threadobject *thread = (threadobject*) t;
689 nativethread *info = &thread->info;
690 info->tid = pthread_self();
691 /* TODO destroy all those things */
692 pthread_mutex_init(&info->joinMutex, NULL);
693 pthread_cond_init(&info->joinCond, NULL);
695 pthread_mutex_init(&thread->waitLock, NULL);
696 pthread_cond_init(&thread->waitCond, NULL);
697 thread->interrupted = false;
698 thread->signaled = false;
699 thread->isSleeping = false;
702 static void initThreadLocks(threadobject *);
706 threadobject *thread;
707 functionptr function;
713 /* threads_startup *************************************************************
715 Thread startup function called by pthread_create.
717 ******************************************************************************/
719 static void *threads_startup_thread(void *t)
721 startupinfo *startup;
722 threadobject *thread;
727 functionptr function;
729 #if defined(ENABLE_INTRP)
730 u1 *intrp_thread_stack;
732 /* create interpreter stack */
735 intrp_thread_stack = (u1 *) alloca(opt_stacksize);
736 MSET(intrp_thread_stack, 0, u1, opt_stacksize);
738 intrp_thread_stack = NULL;
742 /* get passed startupinfo structure and the values in there */
746 thread = startup->thread;
747 function = startup->function;
748 psem = startup->psem;
750 info = &thread->info;
752 /* Seems like we've encountered a situation where info->tid was not set by
753 * pthread_create. We alleviate this problem by waiting for pthread_create
755 threads_sem_wait(startup->psem_first);
758 #if defined(__DARWIN__)
759 info->mach_thread = mach_thread_self();
761 setthreadobject(thread);
763 /* insert the thread into the threadlist */
765 pthread_mutex_lock(&threadlistlock);
767 info->prev = mainthreadobj;
768 info->next = tnext = mainthreadobj->info.next;
769 mainthreadobj->info.next = thread;
770 tnext->info.prev = thread;
772 pthread_mutex_unlock(&threadlistlock);
774 initThreadLocks(thread);
779 setPriority(info->tid, thread->o.thread->priority);
781 #if defined(ENABLE_INTRP)
782 /* set interpreter stack */
785 THREADINFO->_global_sp = (void *) (intrp_thread_stack + opt_stacksize);
788 /* find and run the Thread.run()V method if no other function was passed */
790 if (function == NULL) {
791 method = class_resolveclassmethod(thread->o.header.vftbl->class,
794 thread->o.header.vftbl->class,
800 (void) vm_call_method(method, (java_objectheader *) thread);
804 /* call passed function, e.g. finalizer_thread */
809 /* Allow lock record pools to be used by other threads. They
810 cannot be deleted so we'd better not waste them. */
812 freeLockRecordPools(thread->ee.lrpool);
814 /* remove thread from thread list, do this inside a lock */
816 pthread_mutex_lock(&threadlistlock);
817 info->next->info.prev = info->prev;
818 info->prev->info.next = info->next;
819 pthread_mutex_unlock(&threadlistlock);
821 /* reset thread id (lock on joinMutex? TWISTI) */
823 pthread_mutex_lock(&info->joinMutex);
825 pthread_mutex_unlock(&info->joinMutex);
827 pthread_cond_broadcast(&info->joinCond);
833 /* threads_start_thread ********************************************************
835 Start a thread in the JVM.
837 ******************************************************************************/
839 void threads_start_thread(thread *t, functionptr function)
846 info = &((threadobject *) t->vmThread)->info;
848 /* fill startupinfo structure passed by pthread_create to XXX */
850 startup.thread = (threadobject*) t->vmThread;
851 startup.function = function; /* maybe we don't call Thread.run()V */
853 startup.psem_first = &sem_first;
855 sem_init(&sem, 0, 0);
856 sem_init(&sem_first, 0, 0);
858 if (pthread_create(&info->tid, &threadattr, threads_startup_thread,
860 log_text("pthread_create failed");
864 sem_post(&sem_first);
866 /* wait here until the thread has entered itself into the thread list */
868 threads_sem_wait(&sem);
870 sem_destroy(&sem_first);
874 /* At the end of the program, we wait for all running non-daemon threads to die
877 static threadobject *findNonDaemon(threadobject *thread)
879 while (thread != mainthreadobj) {
880 if (!thread->o.thread->daemon)
882 thread = thread->info.prev;
888 void joinAllThreads()
890 threadobject *thread;
891 pthread_mutex_lock(&threadlistlock);
892 while ((thread = findNonDaemon(mainthreadobj->info.prev)) != NULL) {
893 nativethread *info = &thread->info;
894 pthread_mutex_lock(&info->joinMutex);
895 pthread_mutex_unlock(&threadlistlock);
897 pthread_cond_wait(&info->joinCond, &info->joinMutex);
898 pthread_mutex_unlock(&info->joinMutex);
899 pthread_mutex_lock(&threadlistlock);
901 pthread_mutex_unlock(&threadlistlock);
904 static void initLockRecord(monitorLockRecord *r, threadobject *t)
911 r->incharge = (monitorLockRecord *) &dummyLR;
913 sem_init(&r->queueSem, 0, 0);
914 pthread_mutex_init(&r->resolveLock, NULL);
915 pthread_cond_init(&r->resolveWait, NULL);
918 /* No lock record must ever be destroyed because there may still be references
921 static void destroyLockRecord(monitorLockRecord *r)
923 sem_destroy(&r->queueSem);
924 pthread_mutex_destroy(&r->resolveLock);
925 pthread_cond_destroy(&r->resolveWait);
931 initThreadLocks(mainthreadobj);
934 static void initThreadLocks(threadobject *thread)
936 thread->ee.firstLR = NULL;
937 thread->ee.lrpool = NULL;
938 thread->ee.numlr = 0;
941 static lockRecordPool *allocNewLockRecordPool(threadobject *thread, int size)
943 lockRecordPool *p = mem_alloc(sizeof(lockRecordPoolHeader) + sizeof(monitorLockRecord) * size);
946 p->header.size = size;
947 for (i=0; i<size; i++) {
948 initLockRecord(&p->lr[i], thread);
949 p->lr[i].nextFree = &p->lr[i+1];
951 p->lr[i-1].nextFree = NULL;
955 #define INITIALLOCKRECORDS 8
957 pthread_mutex_t pool_lock;
958 lockRecordPool *global_pool;
960 static void initPools()
962 pthread_mutex_init(&pool_lock, NULL);
965 static lockRecordPool *allocLockRecordPool(threadobject *t, int size)
967 pthread_mutex_lock(&pool_lock);
970 lockRecordPool *pool = global_pool;
971 global_pool = pool->header.next;
972 pthread_mutex_unlock(&pool_lock);
974 for (i=0; i < pool->header.size; i++) {
975 pool->lr[i].ownerThread = t;
976 pool->lr[i].nextFree = &pool->lr[i+1];
978 pool->lr[i-1].nextFree = NULL;
982 pthread_mutex_unlock(&pool_lock);
984 return allocNewLockRecordPool(t, size);
987 static void freeLockRecordPools(lockRecordPool *pool)
989 lockRecordPoolHeader *last;
990 pthread_mutex_lock(&pool_lock);
991 last = &pool->header;
993 last = &last->next->header;
994 last->next = global_pool;
996 pthread_mutex_unlock(&pool_lock);
999 static monitorLockRecord *allocLockRecordSimple(threadobject *t)
1001 monitorLockRecord *r;
1007 int poolsize = t->ee.numlr ? t->ee.numlr * 2 : INITIALLOCKRECORDS;
1008 lockRecordPool *pool = allocLockRecordPool(t, poolsize);
1009 pool->header.next = t->ee.lrpool;
1010 t->ee.lrpool = pool;
1012 t->ee.numlr += pool->header.size;
1015 t->ee.firstLR = r->nextFree;
1017 r->nextFree = NULL; /* in order to find invalid uses of nextFree */
1022 static inline void recycleLockRecord(threadobject *t, monitorLockRecord *r)
1026 assert(r->ownerThread == t);
1027 assert(r->nextFree == NULL);
1029 r->nextFree = t->ee.firstLR;
1033 void initObjectLock(java_objectheader *o)
1037 o->monitorPtr = dummyLR;
1041 /* get_dummyLR *****************************************************************
1043 Returns the global dummy monitor lock record. The pointer is
1044 required in the code generator to set up a virtual
1045 java_objectheader for code patch locking.
1047 *******************************************************************************/
1049 monitorLockRecord *get_dummyLR(void)
1055 static void queueOnLockRecord(monitorLockRecord *lr, java_objectheader *o)
1057 atomic_add(&lr->queuers, 1);
1059 MEMORY_BARRIER_AFTER_ATOMIC();
1062 threads_sem_wait(&lr->queueSem);
1064 atomic_add(&lr->queuers, -1);
1067 static void freeLockRecord(monitorLockRecord *lr)
1074 sem_post(&lr->queueSem);
1077 static inline void handleWaiter(monitorLockRecord *mlr, monitorLockRecord *lr, java_objectheader *o)
1079 if (lr->waiting == o)
1083 monitorLockRecord *monitorEnter(threadobject *t, java_objectheader *o)
1086 monitorLockRecord *lr = o->monitorPtr;
1088 /* the lock record does not lock this object */
1089 monitorLockRecord *nlr;
1090 monitorLockRecord *mlr;
1092 /* allocate a new lock record for this object */
1093 mlr = allocLockRecordSimple(t);
1096 /* check if it is the same record the object refered to earlier */
1099 nlr = o->monitorPtr;
1101 /* the object still refers to the same lock record */
1103 handleWaiter(mlr, lr, o);
1108 /* no, it's another lock record */
1109 /* if we don't own the old record, set incharge XXX */
1110 if (lr->ownerThread != t)
1113 /* if the object still refers to lr, replace it by the new mlr */
1114 MEMORY_BARRIER_BEFORE_ATOMIC();
1115 nlr = (monitorLockRecord *) compare_and_swap((long*) &o->monitorPtr, (long) lr, (long) mlr);
1119 /* we swapped the new record in successfully */
1120 if (mlr == lr || lr->o != o) {
1121 /* the old lock record is the same as the new one, or */
1122 /* it locks another object. */
1124 handleWaiter(mlr, lr, o);
1127 /* lr locks the object, we have to wait */
1129 queueOnLockRecord(lr, o);
1132 handleWaiter(mlr, lr, o);
1136 /* forget this mlr lock record, wait on nlr and try again */
1137 freeLockRecord(mlr);
1138 recycleLockRecord(t, mlr);
1139 queueOnLockRecord(nlr, o);
1142 /* the lock record is for the object we want */
1144 if (lr->ownerThread == t) {
1145 /* we own it already, just recurse */
1150 /* it's locked. we wait and then try again */
1151 queueOnLockRecord(lr, o);
1156 static void wakeWaiters(monitorLockRecord *lr)
1158 monitorLockRecord *tmplr;
1161 /* assign lock record to a temporary variable */
1169 sem_post(&tmplr->queueSem);
1171 tmplr = tmplr->waiter;
1172 } while (tmplr != NULL && tmplr != lr);
1175 #define GRAB_LR(lr,t) \
1176 if (lr->ownerThread != t) { \
1177 lr = lr->incharge; \
1180 #define CHECK_MONITORSTATE(lr,t,mo,a) \
1181 if (lr->o != mo || lr->ownerThread != t) { \
1182 *exceptionptr = new_illegalmonitorstateexception(); \
1186 bool monitorExit(threadobject *t, java_objectheader *o)
1188 monitorLockRecord *lr = o->monitorPtr;
1190 CHECK_MONITORSTATE(lr, t, o, return false);
1192 if (lr->lockCount > 1) {
1193 /* we had locked this one recursively. just decrement, it will */
1194 /* still be locked. */
1200 monitorLockRecord *wlr = lr->waiter;
1201 if (o->monitorPtr != lr ||
1202 (void*) compare_and_swap((long*) &o->monitorPtr, (long) lr, (long) wlr) != lr)
1204 monitorLockRecord *nlr = o->monitorPtr;
1206 STORE_ORDER_BARRIER();
1214 /* unlock and throw away this lock record */
1216 recycleLockRecord(t, lr);
1220 static void removeFromWaiters(monitorLockRecord *lr, monitorLockRecord *wlr)
1223 if (lr->waiter == wlr) {
1224 lr->waiter = wlr->waiter;
1228 } while (lr); /* XXX need to break cycle? */
1231 static inline bool timespec_less(const struct timespec *tv1, const struct timespec *tv2)
1233 return tv1->tv_sec < tv2->tv_sec || (tv1->tv_sec == tv2->tv_sec && tv1->tv_nsec < tv2->tv_nsec);
1236 static bool timeIsEarlier(const struct timespec *tv)
1238 struct timeval tvnow;
1239 struct timespec tsnow;
1240 gettimeofday(&tvnow, NULL);
1241 tsnow.tv_sec = tvnow.tv_sec;
1242 tsnow.tv_nsec = tvnow.tv_usec * 1000;
1243 return timespec_less(&tsnow, tv);
1247 /* waitWithTimeout *************************************************************
1251 *******************************************************************************/
1253 static bool waitWithTimeout(threadobject *t, monitorLockRecord *lr, struct timespec *wakeupTime)
1255 bool wasinterrupted;
1257 pthread_mutex_lock(&t->waitLock);
1259 t->isSleeping = true;
1261 if (wakeupTime->tv_sec || wakeupTime->tv_nsec) {
1262 while (!t->interrupted && !t->signaled && timeIsEarlier(wakeupTime))
1263 pthread_cond_timedwait(&t->waitCond, &t->waitLock, wakeupTime);
1266 while (!t->interrupted && !t->signaled)
1267 pthread_cond_wait(&t->waitCond, &t->waitLock);
1270 wasinterrupted = t->interrupted;
1271 t->interrupted = false;
1272 t->signaled = false;
1273 t->isSleeping = false;
1275 pthread_mutex_unlock(&t->waitLock);
1277 return wasinterrupted;
1281 static void calcAbsoluteTime(struct timespec *tm, s8 millis, s4 nanos)
1283 if (millis || nanos) {
1286 gettimeofday(&tv, NULL);
1287 tv.tv_sec += millis / 1000;
1289 nsec = tv.tv_usec * 1000 + (s4) millis * 1000000 + nanos;
1290 tm->tv_sec = tv.tv_sec + nsec / 1000000000;
1291 tm->tv_nsec = nsec % 1000000000;
1299 void monitorWait(threadobject *t, java_objectheader *o, s8 millis, s4 nanos)
1301 bool wasinterrupted;
1302 struct timespec wakeupTime;
1303 monitorLockRecord *mlr, *lr = o->monitorPtr;
1305 CHECK_MONITORSTATE(lr, t, o, return);
1307 calcAbsoluteTime(&wakeupTime, millis, nanos);
1310 wakeWaiters(lr->waiter);
1312 STORE_ORDER_BARRIER();
1314 wasinterrupted = waitWithTimeout(t, lr, &wakeupTime);
1315 mlr = monitorEnter(t, o);
1316 removeFromWaiters(mlr, lr);
1317 mlr->lockCount = lr->lockCount;
1321 recycleLockRecord(t, lr);
1324 *exceptionptr = new_exception(string_java_lang_InterruptedException);
1327 static void notifyOneOrAll(threadobject *t, java_objectheader *o, bool one)
1329 monitorLockRecord *lr = o->monitorPtr;
1331 CHECK_MONITORSTATE(lr, t, o, return);
1333 threadobject *wthread;
1334 monitorLockRecord *wlr = lr->waiter;
1337 wthread = wlr->ownerThread;
1338 pthread_mutex_lock(&wthread->waitLock);
1339 if (wthread->isSleeping)
1340 pthread_cond_signal(&wthread->waitCond);
1341 wthread->signaled = true;
1342 pthread_mutex_unlock(&wthread->waitLock);
1347 bool threadHoldsLock(threadobject *t, java_objectheader *o)
1349 monitorLockRecord *lr = o->monitorPtr;
1351 /* The reason why we have to check against NULL is that
1352 * dummyLR->incharge == NULL */
1353 return lr->o == o && lr->ownerThread == t;
1356 void interruptThread(java_lang_VMThread *thread)
1358 threadobject *t = (threadobject*) thread;
1360 pthread_mutex_lock(&t->waitLock);
1362 pthread_cond_signal(&t->waitCond);
1363 t->interrupted = true;
1364 pthread_mutex_unlock(&t->waitLock);
1367 bool interruptedThread()
1369 threadobject *t = (threadobject*) THREADOBJECT;
1370 bool intr = t->interrupted;
1371 t->interrupted = false;
1375 bool isInterruptedThread(java_lang_VMThread *thread)
1377 threadobject *t = (threadobject*) thread;
1378 return t->interrupted;
1382 /* thread_sleep ****************************************************************
1384 Sleep the current thread for the specified amount of time.
1386 *******************************************************************************/
1388 void thread_sleep(s8 millis, s4 nanos)
1391 struct timespec wakeupTime;
1392 monitorLockRecord *lr;
1393 bool wasinterrupted;
1395 t = (threadobject *) THREADOBJECT;
1397 calcAbsoluteTime(&wakeupTime, millis, nanos);
1399 lr = allocLockRecordSimple(t);
1401 wasinterrupted = waitWithTimeout(t, lr, &wakeupTime);
1403 recycleLockRecord(t, lr);
1406 *exceptionptr = new_exception(string_java_lang_InterruptedException);
1414 void setPriorityThread(thread *t, s4 priority)
1416 nativethread *info = &((threadobject*) t->vmThread)->info;
1417 setPriority(info->tid, priority);
1420 void wait_cond_for_object(java_objectheader *o, s8 millis, s4 nanos)
1422 threadobject *t = (threadobject*) THREADOBJECT;
1423 monitorWait(t, o, millis, nanos);
1426 void signal_cond_for_object(java_objectheader *o)
1428 threadobject *t = (threadobject*) THREADOBJECT;
1429 notifyOneOrAll(t, o, true);
1432 void broadcast_cond_for_object(java_objectheader *o)
1434 threadobject *t = (threadobject*) THREADOBJECT;
1435 notifyOneOrAll(t, o, false);
1439 /* threads_dump ****************************************************************
1441 Dumps info for all threads running in the JVM. This function is
1442 called when SIGQUIT (<ctrl>-\) is sent to CACAO.
1444 *******************************************************************************/
1446 void threads_dump(void)
1449 java_lang_VMThread *vmt;
1451 java_lang_Thread *t;
1454 tobj = mainthreadobj;
1456 printf("Full thread dump CACAO "VERSION":\n");
1458 /* iterate over all started threads */
1461 /* get thread objects */
1467 /* the thread may be currently in initalization, don't print it */
1470 /* get thread name */
1472 name = javastring_toutf(t->name, false);
1481 #if SIZEOF_VOID_P == 8
1482 printf("prio=%d tid=0x%016lx\n", t->priority, nt->tid);
1484 printf("prio=%d tid=0x%08lx\n", t->priority, nt->tid);
1487 /* send SIGUSR1 to thread to print stacktrace */
1489 pthread_kill(nt->tid, SIGUSR1);
1491 /* sleep this thread a bit, so the signal can reach the thread */
1493 thread_sleep(10, 0);
1496 tobj = tobj->info.next;
1497 } while (tobj && (tobj != mainthreadobj));
1502 * These are local overrides for various environment variables in Emacs.
1503 * Please do not remove this and leave it at the end of the file, where
1504 * Emacs will automagically detect them.
1505 * ---------------------------------------------------------------------
1508 * indent-tabs-mode: t
1512 * vim:noexpandtab:sw=4:ts=4: