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 4867 2006-05-01 23:14:42Z 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_init ************************************************************
156 Initialize a semaphore. Checks against errors and interruptions.
159 sem..............the semaphore to initialize
160 shared...........true if this semaphore will be shared between processes
161 value............the initial value for the semaphore
163 *******************************************************************************/
165 void threads_sem_init(sem_t *sem, bool shared, int value)
172 r = sem_init(sem, shared, value);
175 } while (errno == EINTR);
177 fprintf(stderr,"error: sem_init returned unexpected error %d: %s\n",
178 errno, strerror(errno));
182 /* threads_sem_wait ************************************************************
184 Wait for a semaphore, non-interruptible.
186 IMPORTANT: Always use this function instead of `sem_wait` directly, as
187 `sem_wait` may be interrupted by signals!
190 sem..............the semaphore to wait on
192 *******************************************************************************/
194 void threads_sem_wait(sem_t *sem)
204 } while (errno == EINTR);
206 fprintf(stderr,"error: sem_wait returned unexpected error %d: %s\n",
207 errno, strerror(errno));
211 /* threads_sem_post ************************************************************
213 Increase the count of a semaphore. Checks for errors.
216 sem..............the semaphore to increase the count of
218 *******************************************************************************/
220 void threads_sem_post(sem_t *sem)
226 /* unlike sem_wait, sem_post is not interruptible */
232 fprintf(stderr,"error: sem_post returned unexpected error %d: %s\n",
233 errno, strerror(errno));
237 static void setPriority(pthread_t tid, int priority)
239 struct sched_param schedp;
242 pthread_getschedparam(tid, &policy, &schedp);
243 schedp.sched_priority = priority;
244 pthread_setschedparam(tid, policy, &schedp);
248 static avl_tree *criticaltree;
249 threadobject *mainthreadobj;
251 #ifndef HAVE___THREAD
252 pthread_key_t tkey_threadinfo;
254 __thread threadobject *threadobj;
257 static pthread_mutex_rec_t compiler_mutex;
261 pthread_mutex_lock_rec(&compiler_mutex);
264 void compiler_unlock()
266 pthread_mutex_unlock_rec(&compiler_mutex);
269 static s4 criticalcompare(const void *pa, const void *pb)
271 const threadcritnode *na = pa;
272 const threadcritnode *nb = pb;
274 if (na->mcodebegin < nb->mcodebegin)
276 if (na->mcodebegin > nb->mcodebegin)
282 static const threadcritnode *findcritical(u1 *mcodeptr)
285 const threadcritnode *m;
287 n = criticaltree->root;
294 const threadcritnode *d = n->data;
296 if (mcodeptr == d->mcodebegin)
299 if (mcodeptr < d->mcodebegin) {
320 void thread_registercritical(threadcritnode *n)
322 avl_insert(criticaltree, n);
325 u1 *thread_checkcritical(u1 *mcodeptr)
327 const threadcritnode *n = findcritical(mcodeptr);
328 return (n && mcodeptr < n->mcodeend && mcodeptr > n->mcodebegin) ? n->mcoderestart : NULL;
331 static void thread_addstaticcritical()
333 /* XXX TWISTI: this is just a quick hack */
334 #if defined(ENABLE_JIT)
335 threadcritnode *n = &asm_criticalsections;
337 while (n->mcodebegin)
338 thread_registercritical(n++);
342 static pthread_mutex_t threadlistlock;
344 static pthread_mutex_t stopworldlock;
345 volatile int stopworldwhere;
347 static sem_t suspend_ack;
348 #if defined(__MIPS__)
349 static pthread_mutex_t suspend_ack_lock = PTHREAD_MUTEX_INITIALIZER;
350 static pthread_cond_t suspend_cond = PTHREAD_COND_INITIALIZER;
354 * where - 1 from within GC
357 void lock_stopworld(int where)
359 pthread_mutex_lock(&stopworldlock);
360 stopworldwhere = where;
363 void unlock_stopworld()
366 pthread_mutex_unlock(&stopworldlock);
369 #if !defined(__DARWIN__)
370 /* Caller must hold threadlistlock */
371 static int cast_sendsignals(int sig, int count)
374 threadobject *tobj = mainthreadobj;
375 nativethread *infoself = THREADINFO;
380 tobj = tobj->info.next;
381 } while (tobj != mainthreadobj);
385 nativethread *info = &tobj->info;
386 if (info != infoself)
387 pthread_kill(info->tid, sig);
388 tobj = tobj->info.next;
389 } while (tobj != mainthreadobj);
396 static void cast_darwinstop()
398 threadobject *tobj = mainthreadobj;
399 nativethread *infoself = THREADINFO;
402 nativethread *info = &tobj->info;
403 if (info != infoself)
405 thread_state_flavor_t flavor = PPC_THREAD_STATE;
406 mach_msg_type_number_t thread_state_count = PPC_THREAD_STATE_COUNT;
407 ppc_thread_state_t thread_state;
408 mach_port_t thread = info->mach_thread;
411 r = thread_suspend(thread);
412 if (r != KERN_SUCCESS) {
413 log_text("thread_suspend failed");
417 r = thread_get_state(thread, flavor,
418 (natural_t*)&thread_state, &thread_state_count);
419 if (r != KERN_SUCCESS) {
420 log_text("thread_get_state failed");
424 thread_restartcriticalsection(&thread_state);
426 r = thread_set_state(thread, flavor,
427 (natural_t*)&thread_state, thread_state_count);
428 if (r != KERN_SUCCESS) {
429 log_text("thread_set_state failed");
433 tobj = tobj->info.next;
434 } while (tobj != mainthreadobj);
437 static void cast_darwinresume()
439 threadobject *tobj = mainthreadobj;
440 nativethread *infoself = THREADINFO;
443 nativethread *info = &tobj->info;
444 if (info != infoself)
446 mach_port_t thread = info->mach_thread;
449 r = thread_resume(thread);
450 if (r != KERN_SUCCESS) {
451 log_text("thread_resume failed");
455 tobj = tobj->info.next;
456 } while (tobj != mainthreadobj);
461 #if defined(__MIPS__)
462 static void cast_irixresume()
464 pthread_mutex_lock(&suspend_ack_lock);
465 pthread_cond_broadcast(&suspend_cond);
466 pthread_mutex_unlock(&suspend_ack_lock);
470 void cast_stopworld()
474 pthread_mutex_lock(&threadlistlock);
475 #if defined(__DARWIN__)
478 count = cast_sendsignals(GC_signum1(), 0);
479 for (i=0; i<count; i++)
480 threads_sem_wait(&suspend_ack);
482 pthread_mutex_unlock(&threadlistlock);
485 void cast_startworld()
487 pthread_mutex_lock(&threadlistlock);
488 #if defined(__DARWIN__)
490 #elif defined(__MIPS__)
493 cast_sendsignals(GC_signum2(), -1);
495 pthread_mutex_unlock(&threadlistlock);
499 #if !defined(__DARWIN__)
500 static void sigsuspend_handler(ucontext_t *ctx)
505 /* XXX TWISTI: this is just a quick hack */
506 #if defined(ENABLE_JIT)
507 thread_restartcriticalsection(ctx);
510 /* Do as Boehm does. On IRIX a condition variable is used for wake-up
511 (not POSIX async-safe). */
512 #if defined(__IRIX__)
513 pthread_mutex_lock(&suspend_ack_lock);
514 threads_sem_post(&suspend_ack);
515 pthread_cond_wait(&suspend_cond, &suspend_ack_lock);
516 pthread_mutex_unlock(&suspend_ack_lock);
518 threads_sem_post(&suspend_ack);
522 sigdelset(&sigs, sig);
527 int cacao_suspendhandler(ucontext_t *ctx)
529 if (stopworldwhere != 2)
532 sigsuspend_handler(ctx);
537 #if !defined(ENABLE_JVMTI)
538 static void setthreadobject(threadobject *thread)
540 void setthreadobject(threadobject *thread)
543 #if !defined(HAVE___THREAD)
544 pthread_setspecific(tkey_threadinfo, thread);
551 /* thread_setself **************************************************************
553 Return the threadobject of the current thread.
555 XXX The return value type should be changed to a typed pointer.
557 *******************************************************************************/
559 void *thread_getself(void)
564 /* unlocked dummy record - avoids NULL checks */
565 static monitorLockRecord *dummyLR;
567 static void initPools();
570 /* thread_preinit **************************************************************
572 Do some early initialization of stuff required.
574 *******************************************************************************/
576 void threads_preinit(void)
579 pthread_mutexattr_t mutexattr;
580 pthread_mutexattr_init(&mutexattr);
581 pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_RECURSIVE);
582 pthread_mutex_init(&compiler_mutex, &mutexattr);
583 pthread_mutexattr_destroy(&mutexattr);
585 pthread_mutex_init_rec(&compiler_mutex);
588 pthread_mutex_init(&threadlistlock, NULL);
589 pthread_mutex_init(&stopworldlock, NULL);
591 /* Allocate something so the garbage collector's signal handlers
593 heap_allocate(1, false, NULL);
595 mainthreadobj = NEW(threadobject);
596 mainthreadobj->info.tid = pthread_self();
597 #if !defined(HAVE___THREAD)
598 pthread_key_create(&tkey_threadinfo, NULL);
600 setthreadobject(mainthreadobj);
603 /* Every newly created object's monitorPtr points here so we save
604 a check against NULL */
606 dummyLR = NEW(monitorLockRecord);
608 dummyLR->ownerThread = NULL;
609 dummyLR->waiting = NULL;
610 dummyLR->incharge = dummyLR;
612 /* we need a working dummyLR before initializing the critical
615 criticaltree = avl_create(&criticalcompare);
617 thread_addstaticcritical();
618 threads_sem_init(&suspend_ack, 0, 0);
622 static pthread_attr_t threadattr;
624 static void freeLockRecordPools(lockRecordPool *);
627 /* threads_init ****************************************************************
629 Initializes the threads required by the JVM: main, finalizer.
631 *******************************************************************************/
633 bool threads_init(u1 *stackbottom)
635 java_lang_String *threadname;
636 java_lang_Thread *mainthread;
637 java_lang_ThreadGroup *threadgroup;
638 threadobject *tempthread;
641 tempthread = mainthreadobj;
643 freeLockRecordPools(mainthreadobj->ee.lrpool);
645 /* This is kinda tricky, we grow the java.lang.Thread object so we
646 can keep the execution environment there. No Thread object must
647 have been created at an earlier time. */
649 class_java_lang_VMThread->instancesize = sizeof(threadobject);
651 /* create a VMThread */
653 mainthreadobj = (threadobject *) builtin_new(class_java_lang_VMThread);
658 FREE(tempthread, threadobject);
660 initThread(&mainthreadobj->o);
662 setthreadobject(mainthreadobj);
666 mainthreadobj->info.next = mainthreadobj;
667 mainthreadobj->info.prev = mainthreadobj;
669 #if defined(ENABLE_INTRP)
670 /* create interpreter stack */
673 MSET(intrp_main_stack, 0, u1, opt_stacksize);
674 mainthreadobj->info._global_sp = intrp_main_stack + opt_stacksize;
678 threadname = javastring_new(utf_new_char("main"));
680 /* allocate and init ThreadGroup */
682 threadgroup = (java_lang_ThreadGroup *)
683 native_new_and_init(class_java_lang_ThreadGroup);
686 throw_exception_exit();
688 /* create a Thread */
690 mainthread = (java_lang_Thread *) builtin_new(class_java_lang_Thread);
693 throw_exception_exit();
695 mainthreadobj->o.thread = mainthread;
697 /* call Thread.<init>(Ljava/lang/VMThread;Ljava/lang/String;IZ)V */
699 method = class_resolveclassmethod(class_java_lang_Thread,
701 utf_new_char("(Ljava/lang/VMThread;Ljava/lang/String;IZ)V"),
702 class_java_lang_Thread,
708 (void) vm_call_method(method, (java_objectheader *) mainthread,
709 mainthreadobj, threadname, 5, false);
714 mainthread->group = threadgroup;
716 /* add mainthread to ThreadGroup */
718 method = class_resolveclassmethod(class_java_lang_ThreadGroup,
719 utf_new_char("addThread"),
720 utf_new_char("(Ljava/lang/Thread;)V"),
721 class_java_lang_ThreadGroup,
727 (void) vm_call_method(method, (java_objectheader *) threadgroup,
733 setPriority(pthread_self(), 5);
735 pthread_attr_init(&threadattr);
736 pthread_attr_setdetachstate(&threadattr, PTHREAD_CREATE_DETACHED);
738 /* everything's ok */
744 void initThread(java_lang_VMThread *t)
746 threadobject *thread = (threadobject*) t;
747 nativethread *info = &thread->info;
748 info->tid = pthread_self();
749 /* TODO destroy all those things */
750 pthread_mutex_init(&info->joinMutex, NULL);
751 pthread_cond_init(&info->joinCond, NULL);
753 pthread_mutex_init(&thread->waitLock, NULL);
754 pthread_cond_init(&thread->waitCond, NULL);
755 thread->interrupted = false;
756 thread->signaled = false;
757 thread->isSleeping = false;
760 static void initThreadLocks(threadobject *);
763 /* startupinfo *****************************************************************
765 Struct used to pass info from threads_start_thread to
766 threads_startup_thread.
768 ******************************************************************************/
771 threadobject *thread; /* threadobject for this thread */
772 functionptr function; /* function to run in the new thread */
773 sem_t *psem; /* signals when thread has been entered */
774 /* in the thread list */
775 sem_t *psem_first; /* signals when pthread_create has returned */
779 /* threads_startup_thread ******************************************************
781 Thread startup function called by pthread_create.
783 NOTE: This function is not called directly by pthread_create. The Boehm GC
784 inserts its own GC_start_routine in between, which then calls
788 t............the argument passed to pthread_create, ie. a pointer to
789 a startupinfo struct. CAUTION: When the `psem` semaphore
790 is posted, the startupinfo struct becomes invalid! (It
791 is allocated on the stack of threads_start_thread.)
793 ******************************************************************************/
795 static void *threads_startup_thread(void *t)
797 startupinfo *startup;
798 threadobject *thread;
803 functionptr function;
805 #if defined(ENABLE_INTRP)
806 u1 *intrp_thread_stack;
808 /* create interpreter stack */
811 intrp_thread_stack = (u1 *) alloca(opt_stacksize);
812 MSET(intrp_thread_stack, 0, u1, opt_stacksize);
814 intrp_thread_stack = NULL;
818 /* get passed startupinfo structure and the values in there */
821 t = NULL; /* make sure it's not used wrongly */
823 thread = startup->thread;
824 function = startup->function;
825 psem = startup->psem;
827 info = &thread->info;
829 /* Seems like we've encountered a situation where info->tid was not set by
830 * pthread_create. We alleviate this problem by waiting for pthread_create
832 threads_sem_wait(startup->psem_first);
834 /* set the thread object */
836 #if defined(__DARWIN__)
837 info->mach_thread = mach_thread_self();
839 setthreadobject(thread);
841 /* insert the thread into the threadlist */
843 pthread_mutex_lock(&threadlistlock);
845 info->prev = mainthreadobj;
846 info->next = tnext = mainthreadobj->info.next;
847 mainthreadobj->info.next = thread;
848 tnext->info.prev = thread;
850 pthread_mutex_unlock(&threadlistlock);
852 /* init data structures of this thread */
854 initThreadLocks(thread);
856 /* tell threads_startup_thread that we registered ourselves */
857 /* CAUTION: *startup becomes invalid with this! */
860 threads_sem_post(psem);
862 /* set our priority */
864 setPriority(info->tid, thread->o.thread->priority);
866 #if defined(ENABLE_INTRP)
867 /* set interpreter stack */
870 THREADINFO->_global_sp = (void *) (intrp_thread_stack + opt_stacksize);
873 /* find and run the Thread.run()V method if no other function was passed */
875 if (function == NULL) {
876 method = class_resolveclassmethod(thread->o.header.vftbl->class,
879 thread->o.header.vftbl->class,
885 (void) vm_call_method(method, (java_objectheader *) thread);
889 /* call passed function, e.g. finalizer_thread */
894 /* Allow lock record pools to be used by other threads. They
895 cannot be deleted so we'd better not waste them. */
897 freeLockRecordPools(thread->ee.lrpool);
899 /* remove thread from thread list, do this inside a lock */
901 pthread_mutex_lock(&threadlistlock);
902 info->next->info.prev = info->prev;
903 info->prev->info.next = info->next;
904 pthread_mutex_unlock(&threadlistlock);
906 /* reset thread id (lock on joinMutex? TWISTI) */
908 pthread_mutex_lock(&info->joinMutex);
910 pthread_mutex_unlock(&info->joinMutex);
912 /* tell everyone that a thread has finished */
914 pthread_cond_broadcast(&info->joinCond);
920 /* threads_start_thread ********************************************************
922 Start a thread in the JVM.
925 t............the java.lang.Thread object
926 function.....function to run in the new thread. NULL means that the
927 "run" method of the object `t` should be called
929 ******************************************************************************/
931 void threads_start_thread(thread *t, functionptr function)
938 info = &((threadobject *) t->vmThread)->info;
940 /* fill startupinfo structure passed by pthread_create to
941 * threads_startup_thread */
943 startup.thread = (threadobject*) t->vmThread;
944 startup.function = function; /* maybe we don't call Thread.run()V */
946 startup.psem_first = &sem_first;
948 threads_sem_init(&sem, 0, 0);
949 threads_sem_init(&sem_first, 0, 0);
951 /* create the thread */
953 if (pthread_create(&info->tid, &threadattr, threads_startup_thread,
955 log_text("pthread_create failed");
959 /* signal that pthread_create has returned, so info->tid is valid */
961 threads_sem_post(&sem_first);
963 /* wait here until the thread has entered itself into the thread list */
965 threads_sem_wait(&sem);
970 sem_destroy(&sem_first);
974 /* At the end of the program, we wait for all running non-daemon threads to die
977 static threadobject *findNonDaemon(threadobject *thread)
979 while (thread != mainthreadobj) {
980 if (!thread->o.thread->daemon)
982 thread = thread->info.prev;
988 void joinAllThreads()
990 threadobject *thread;
991 pthread_mutex_lock(&threadlistlock);
992 while ((thread = findNonDaemon(mainthreadobj->info.prev)) != NULL) {
993 nativethread *info = &thread->info;
994 pthread_mutex_lock(&info->joinMutex);
995 pthread_mutex_unlock(&threadlistlock);
997 pthread_cond_wait(&info->joinCond, &info->joinMutex);
998 pthread_mutex_unlock(&info->joinMutex);
999 pthread_mutex_lock(&threadlistlock);
1001 pthread_mutex_unlock(&threadlistlock);
1004 static void initLockRecord(monitorLockRecord *r, threadobject *t)
1011 r->incharge = (monitorLockRecord *) &dummyLR;
1013 threads_sem_init(&r->queueSem, 0, 0);
1014 pthread_mutex_init(&r->resolveLock, NULL);
1015 pthread_cond_init(&r->resolveWait, NULL);
1020 initThreadLocks(mainthreadobj);
1023 static void initThreadLocks(threadobject *thread)
1025 thread->ee.firstLR = NULL;
1026 thread->ee.lrpool = NULL;
1027 thread->ee.numlr = 0;
1030 static lockRecordPool *allocNewLockRecordPool(threadobject *thread, int size)
1032 lockRecordPool *p = mem_alloc(sizeof(lockRecordPoolHeader) + sizeof(monitorLockRecord) * size);
1035 p->header.size = size;
1036 for (i=0; i<size; i++) {
1037 initLockRecord(&p->lr[i], thread);
1038 p->lr[i].nextFree = &p->lr[i+1];
1040 p->lr[i-1].nextFree = NULL;
1044 #define INITIALLOCKRECORDS 8
1046 pthread_mutex_t pool_lock;
1047 lockRecordPool *global_pool;
1049 static void initPools()
1051 pthread_mutex_init(&pool_lock, NULL);
1054 static lockRecordPool *allocLockRecordPool(threadobject *t, int size)
1056 pthread_mutex_lock(&pool_lock);
1059 lockRecordPool *pool = global_pool;
1060 global_pool = pool->header.next;
1061 pthread_mutex_unlock(&pool_lock);
1063 for (i=0; i < pool->header.size; i++) {
1064 pool->lr[i].ownerThread = t;
1065 pool->lr[i].nextFree = &pool->lr[i+1];
1067 pool->lr[i-1].nextFree = NULL;
1071 pthread_mutex_unlock(&pool_lock);
1073 return allocNewLockRecordPool(t, size);
1076 static void freeLockRecordPools(lockRecordPool *pool)
1078 lockRecordPoolHeader *last;
1079 pthread_mutex_lock(&pool_lock);
1080 last = &pool->header;
1082 last = &last->next->header;
1083 last->next = global_pool;
1085 pthread_mutex_unlock(&pool_lock);
1088 static monitorLockRecord *allocLockRecordSimple(threadobject *t)
1090 monitorLockRecord *r;
1096 int poolsize = t->ee.numlr ? t->ee.numlr * 2 : INITIALLOCKRECORDS;
1097 lockRecordPool *pool = allocLockRecordPool(t, poolsize);
1098 pool->header.next = t->ee.lrpool;
1099 t->ee.lrpool = pool;
1101 t->ee.numlr += pool->header.size;
1104 t->ee.firstLR = r->nextFree;
1106 r->nextFree = NULL; /* in order to find invalid uses of nextFree */
1111 static inline void recycleLockRecord(threadobject *t, monitorLockRecord *r)
1115 assert(r->ownerThread == t);
1116 assert(r->nextFree == NULL);
1118 r->nextFree = t->ee.firstLR;
1122 /* initObjectLock **************************************************************
1124 Initialize the monitor pointer of the given object. The monitor gets
1125 initialized to an unlocked state.
1127 *******************************************************************************/
1129 void initObjectLock(java_objectheader *o)
1133 o->monitorPtr = dummyLR;
1137 /* get_dummyLR *****************************************************************
1139 Returns the global dummy monitor lock record. The pointer is
1140 required in the code generator to set up a virtual
1141 java_objectheader for code patch locking.
1143 *******************************************************************************/
1145 monitorLockRecord *get_dummyLR(void)
1151 static void queueOnLockRecord(monitorLockRecord *lr, java_objectheader *o)
1153 atomic_add(&lr->queuers, 1);
1155 MEMORY_BARRIER_AFTER_ATOMIC();
1158 threads_sem_wait(&lr->queueSem);
1160 atomic_add(&lr->queuers, -1);
1163 static void freeLockRecord(monitorLockRecord *lr)
1170 threads_sem_post(&lr->queueSem);
1173 static inline void handleWaiter(monitorLockRecord *mlr, monitorLockRecord *lr, java_objectheader *o)
1175 if (lr->waiting == o)
1179 monitorLockRecord *monitorEnter(threadobject *t, java_objectheader *o)
1182 monitorLockRecord *lr = o->monitorPtr;
1184 /* the lock record does not lock this object */
1185 monitorLockRecord *nlr;
1186 monitorLockRecord *mlr;
1188 /* allocate a new lock record for this object */
1189 mlr = allocLockRecordSimple(t);
1192 /* check if it is the same record the object refered to earlier */
1195 nlr = o->monitorPtr;
1197 /* the object still refers to the same lock record */
1199 handleWaiter(mlr, lr, o);
1204 /* no, it's another lock record */
1205 /* if we don't own the old record, set incharge XXX */
1206 if (lr->ownerThread != t)
1209 /* if the object still refers to lr, replace it by the new mlr */
1210 MEMORY_BARRIER_BEFORE_ATOMIC();
1211 nlr = (monitorLockRecord *) compare_and_swap((long*) &o->monitorPtr, (long) lr, (long) mlr);
1215 /* we swapped the new record in successfully */
1216 if (mlr == lr || lr->o != o) {
1217 /* the old lock record is the same as the new one, or */
1218 /* it locks another object. */
1220 handleWaiter(mlr, lr, o);
1223 /* lr locks the object, we have to wait */
1225 queueOnLockRecord(lr, o);
1228 handleWaiter(mlr, lr, o);
1232 /* forget this mlr lock record, wait on nlr and try again */
1233 freeLockRecord(mlr);
1234 recycleLockRecord(t, mlr);
1235 queueOnLockRecord(nlr, o);
1238 /* the lock record is for the object we want */
1240 if (lr->ownerThread == t) {
1241 /* we own it already, just recurse */
1246 /* it's locked. we wait and then try again */
1247 queueOnLockRecord(lr, o);
1252 static void wakeWaiters(monitorLockRecord *lr)
1254 monitorLockRecord *tmplr;
1257 /* assign lock record to a temporary variable */
1265 threads_sem_post(&tmplr->queueSem);
1267 tmplr = tmplr->waiter;
1268 } while (tmplr != NULL && tmplr != lr);
1271 #define GRAB_LR(lr,t) \
1272 if (lr->ownerThread != t) { \
1273 lr = lr->incharge; \
1276 #define CHECK_MONITORSTATE(lr,t,mo,a) \
1277 if (lr->o != mo || lr->ownerThread != t) { \
1278 *exceptionptr = new_illegalmonitorstateexception(); \
1282 bool monitorExit(threadobject *t, java_objectheader *o)
1284 monitorLockRecord *lr = o->monitorPtr;
1286 CHECK_MONITORSTATE(lr, t, o, return false);
1288 if (lr->lockCount > 1) {
1289 /* we had locked this one recursively. just decrement, it will */
1290 /* still be locked. */
1296 monitorLockRecord *wlr = lr->waiter;
1297 if (o->monitorPtr != lr ||
1298 (void*) compare_and_swap((long*) &o->monitorPtr, (long) lr, (long) wlr) != lr)
1300 monitorLockRecord *nlr = o->monitorPtr;
1302 STORE_ORDER_BARRIER();
1310 /* unlock and throw away this lock record */
1312 recycleLockRecord(t, lr);
1316 static void removeFromWaiters(monitorLockRecord *lr, monitorLockRecord *wlr)
1319 if (lr->waiter == wlr) {
1320 lr->waiter = wlr->waiter;
1324 } while (lr); /* XXX need to break cycle? */
1327 static inline bool timespec_less(const struct timespec *tv1, const struct timespec *tv2)
1329 return tv1->tv_sec < tv2->tv_sec || (tv1->tv_sec == tv2->tv_sec && tv1->tv_nsec < tv2->tv_nsec);
1332 static bool timeIsEarlier(const struct timespec *tv)
1334 struct timeval tvnow;
1335 struct timespec tsnow;
1336 gettimeofday(&tvnow, NULL);
1337 tsnow.tv_sec = tvnow.tv_sec;
1338 tsnow.tv_nsec = tvnow.tv_usec * 1000;
1339 return timespec_less(&tsnow, tv);
1343 /* waitWithTimeout *************************************************************
1347 *******************************************************************************/
1349 static bool waitWithTimeout(threadobject *t, monitorLockRecord *lr, struct timespec *wakeupTime)
1351 bool wasinterrupted;
1353 pthread_mutex_lock(&t->waitLock);
1355 t->isSleeping = true;
1357 if (wakeupTime->tv_sec || wakeupTime->tv_nsec) {
1358 while (!t->interrupted && !t->signaled && timeIsEarlier(wakeupTime))
1359 pthread_cond_timedwait(&t->waitCond, &t->waitLock, wakeupTime);
1362 while (!t->interrupted && !t->signaled)
1363 pthread_cond_wait(&t->waitCond, &t->waitLock);
1366 wasinterrupted = t->interrupted;
1367 t->interrupted = false;
1368 t->signaled = false;
1369 t->isSleeping = false;
1371 pthread_mutex_unlock(&t->waitLock);
1373 return wasinterrupted;
1377 static void calcAbsoluteTime(struct timespec *tm, s8 millis, s4 nanos)
1379 if (millis || nanos) {
1382 gettimeofday(&tv, NULL);
1383 tv.tv_sec += millis / 1000;
1385 nsec = tv.tv_usec * 1000 + (s4) millis * 1000000 + nanos;
1386 tm->tv_sec = tv.tv_sec + nsec / 1000000000;
1387 tm->tv_nsec = nsec % 1000000000;
1395 void monitorWait(threadobject *t, java_objectheader *o, s8 millis, s4 nanos)
1397 bool wasinterrupted;
1398 struct timespec wakeupTime;
1399 monitorLockRecord *mlr, *lr = o->monitorPtr;
1401 CHECK_MONITORSTATE(lr, t, o, return);
1403 calcAbsoluteTime(&wakeupTime, millis, nanos);
1406 wakeWaiters(lr->waiter);
1408 STORE_ORDER_BARRIER();
1410 wasinterrupted = waitWithTimeout(t, lr, &wakeupTime);
1411 mlr = monitorEnter(t, o);
1412 removeFromWaiters(mlr, lr);
1413 mlr->lockCount = lr->lockCount;
1417 recycleLockRecord(t, lr);
1420 *exceptionptr = new_exception(string_java_lang_InterruptedException);
1423 static void notifyOneOrAll(threadobject *t, java_objectheader *o, bool one)
1425 monitorLockRecord *lr = o->monitorPtr;
1427 CHECK_MONITORSTATE(lr, t, o, return);
1429 threadobject *wthread;
1430 monitorLockRecord *wlr = lr->waiter;
1433 wthread = wlr->ownerThread;
1434 pthread_mutex_lock(&wthread->waitLock);
1435 if (wthread->isSleeping)
1436 pthread_cond_signal(&wthread->waitCond);
1437 wthread->signaled = true;
1438 pthread_mutex_unlock(&wthread->waitLock);
1443 bool threadHoldsLock(threadobject *t, java_objectheader *o)
1445 monitorLockRecord *lr = o->monitorPtr;
1447 /* The reason why we have to check against NULL is that
1448 * dummyLR->incharge == NULL */
1449 return lr->o == o && lr->ownerThread == t;
1452 void interruptThread(java_lang_VMThread *thread)
1454 threadobject *t = (threadobject*) thread;
1456 pthread_mutex_lock(&t->waitLock);
1458 pthread_cond_signal(&t->waitCond);
1459 t->interrupted = true;
1460 pthread_mutex_unlock(&t->waitLock);
1463 bool interruptedThread()
1465 threadobject *t = (threadobject*) THREADOBJECT;
1466 bool intr = t->interrupted;
1467 t->interrupted = false;
1471 bool isInterruptedThread(java_lang_VMThread *thread)
1473 threadobject *t = (threadobject*) thread;
1474 return t->interrupted;
1478 /* thread_sleep ****************************************************************
1480 Sleep the current thread for the specified amount of time.
1482 *******************************************************************************/
1484 void thread_sleep(s8 millis, s4 nanos)
1487 struct timespec wakeupTime;
1488 monitorLockRecord *lr;
1489 bool wasinterrupted;
1491 t = (threadobject *) THREADOBJECT;
1493 calcAbsoluteTime(&wakeupTime, millis, nanos);
1495 lr = allocLockRecordSimple(t);
1497 wasinterrupted = waitWithTimeout(t, lr, &wakeupTime);
1499 recycleLockRecord(t, lr);
1502 *exceptionptr = new_exception(string_java_lang_InterruptedException);
1510 void setPriorityThread(thread *t, s4 priority)
1512 nativethread *info = &((threadobject*) t->vmThread)->info;
1513 setPriority(info->tid, priority);
1516 void wait_cond_for_object(java_objectheader *o, s8 millis, s4 nanos)
1518 threadobject *t = (threadobject*) THREADOBJECT;
1519 monitorWait(t, o, millis, nanos);
1522 void signal_cond_for_object(java_objectheader *o)
1524 threadobject *t = (threadobject*) THREADOBJECT;
1525 notifyOneOrAll(t, o, true);
1528 void broadcast_cond_for_object(java_objectheader *o)
1530 threadobject *t = (threadobject*) THREADOBJECT;
1531 notifyOneOrAll(t, o, false);
1535 /* threads_dump ****************************************************************
1537 Dumps info for all threads running in the JVM. This function is
1538 called when SIGQUIT (<ctrl>-\) is sent to CACAO.
1540 *******************************************************************************/
1542 void threads_dump(void)
1545 java_lang_VMThread *vmt;
1547 java_lang_Thread *t;
1550 tobj = mainthreadobj;
1552 printf("Full thread dump CACAO "VERSION":\n");
1554 /* iterate over all started threads */
1557 /* get thread objects */
1563 /* the thread may be currently in initalization, don't print it */
1566 /* get thread name */
1568 name = javastring_toutf(t->name, false);
1577 #if SIZEOF_VOID_P == 8
1578 printf("prio=%d tid=0x%016lx\n", t->priority, nt->tid);
1580 printf("prio=%d tid=0x%08lx\n", t->priority, nt->tid);
1583 /* send SIGUSR1 to thread to print stacktrace */
1585 pthread_kill(nt->tid, SIGUSR1);
1587 /* sleep this thread a bit, so the signal can reach the thread */
1589 thread_sleep(10, 0);
1592 tobj = tobj->info.next;
1593 } while (tobj && (tobj != mainthreadobj));
1598 * These are local overrides for various environment variables in Emacs.
1599 * Please do not remove this and leave it at the end of the file, where
1600 * Emacs will automagically detect them.
1601 * ---------------------------------------------------------------------
1604 * indent-tabs-mode: t
1608 * vim:noexpandtab:sw=4:ts=4: