X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=src%2Fthreads%2Fnative%2Fthreads.c;h=a2dd4de09d22b0081ddf883e0b0ec19c7e9a0691;hb=9f859ad50d3d5d98c185d40b86b2179bc4dc9aeb;hp=e7841220bc1b90954524374399cdf10895b6d5dd;hpb=eb875e9dd2be3b22e60ed69b4a323762b783a93a;p=cacao.git diff --git a/src/threads/native/threads.c b/src/threads/native/threads.c index e7841220b..a2dd4de09 100644 --- a/src/threads/native/threads.c +++ b/src/threads/native/threads.c @@ -22,8 +22,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - $Id: threads.c 7338 2007-02-13 00:17:22Z twisti $ - */ @@ -57,6 +55,7 @@ #include "mm/memory.h" #include "native/jni.h" +#include "native/llni.h" #include "native/native.h" #include "native/include/java_lang_Object.h" #include "native/include/java_lang_String.h" @@ -71,11 +70,11 @@ # include "native/include/java_lang_VMThread.h" #endif +#include "threads/lock-common.h" #include "threads/threads-common.h" #include "threads/native/threads.h" -#include "toolbox/avl.h" #include "toolbox/logging.h" #include "vm/builtin.h" @@ -88,6 +87,10 @@ #include "vmcore/options.h" +#if defined(ENABLE_STATISTICS) +# include "vmcore/statistics.h" +#endif + #if !defined(__DARWIN__) # if defined(__LINUX__) # define GC_LINUX_THREADS @@ -185,8 +188,6 @@ static int sem_destroy(sem_t *sem) #define STOPWORLD_FROM_GC 1 #define STOPWORLD_FROM_CLASS_NUMBERING 2 -#define THREADS_INITIAL_TABLE_SIZE 8 - /* startupinfo ***************************************************************** @@ -206,22 +207,13 @@ typedef struct { /* prototypes *****************************************************************/ -static void threads_table_init(void); -static s4 threads_table_add(threadobject *thread); -static void threads_table_remove(threadobject *thread); static void threads_calc_absolute_time(struct timespec *tm, s8 millis, s4 nanos); -#if !defined(NDEBUG) && 0 -static void threads_table_dump(FILE *file); -#endif /******************************************************************************/ /* GLOBAL VARIABLES */ /******************************************************************************/ -/* the main thread */ -threadobject *mainthreadobj; - static methodinfo *method_thread_init; /* the thread object of the current thread */ @@ -233,18 +225,21 @@ __thread threadobject *threads_current_threadobject; pthread_key_t threads_current_threadobject_key; #endif -/* global threads table */ -static threads_table_t threads_table; - -/* global compiler mutex */ -static pthread_mutex_t compiler_mutex; - -/* global mutex for changing the thread list */ -static pthread_mutex_t threadlistlock; +/* global mutex for the threads table */ +static pthread_mutex_t mutex_threads_list; /* global mutex for stop-the-world */ static pthread_mutex_t stopworldlock; +/* global mutex and condition for joining threads on exit */ +static pthread_mutex_t mutex_join; +static pthread_cond_t cond_join; + +/* XXX We disable that whole bunch of code until we have the exact-GC + running. */ + +#if 0 + /* this is one of the STOPWORLD_FROM_ constants, telling why the world is */ /* being stopped */ static volatile int stopworldwhere; @@ -256,7 +251,7 @@ static pthread_mutex_t suspend_ack_lock = PTHREAD_MUTEX_INITIALIZER; static pthread_cond_t suspend_cond = PTHREAD_COND_INITIALIZER; #endif -static pthread_attr_t threadattr; +#endif /* 0 */ /* mutexes used by the fake atomic instructions */ #if defined(USE_FAKE_ATOMIC_INSTRUCTIONS) @@ -346,30 +341,6 @@ void threads_sem_post(sem_t *sem) } -/* compiler_lock *************************************************************** - - Enter the compiler lock. - -******************************************************************************/ - -void compiler_lock(void) -{ - pthread_mutex_lock(&compiler_mutex); -} - - -/* compiler_unlock ************************************************************* - - Release the compiler lock. - -******************************************************************************/ - -void compiler_unlock(void) -{ - pthread_mutex_unlock(&compiler_mutex); -} - - /* lock_stopworld ************************************************************** Enter the stopworld lock, specifying why the world shall be stopped. @@ -383,7 +354,7 @@ void compiler_unlock(void) void lock_stopworld(int where) { pthread_mutex_lock(&stopworldlock); - stopworldwhere = where; +/* stopworldwhere = where; */ } @@ -395,34 +366,51 @@ void lock_stopworld(int where) void unlock_stopworld(void) { - stopworldwhere = 0; +/* stopworldwhere = 0; */ pthread_mutex_unlock(&stopworldlock); } +/* XXX We disable that whole bunch of code until we have the exact-GC + running. */ + +#if 0 + #if !defined(__DARWIN__) /* Caller must hold threadlistlock */ -static int threads_cast_sendsignals(int sig, int count) +static s4 threads_cast_sendsignals(s4 sig) { - /* Count threads */ - threadobject *tobj = mainthreadobj; - threadobject *self = THREADOBJECT; + threadobject *t; + threadobject *self; + s4 count; - if (count == 0) { - do { - count++; - tobj = tobj->next; - } while (tobj != mainthreadobj); - } + self = THREADOBJECT; - assert(tobj == mainthreadobj); + /* iterate over all started threads */ - do { - if (tobj != self) - pthread_kill(tobj->tid, sig); - tobj = tobj->next; - } while (tobj != mainthreadobj); + count = 0; - return count - 1; + for (t = threads_list_first(); t != NULL; t = threads_list_next(t)) { + /* don't send the signal to ourself */ + + if (t == self) + continue; + + /* don't send the signal to NEW threads (because they are not + completely initialized) */ + + if (t->state == THREAD_STATE_NEW) + continue; + + /* send the signal */ + + pthread_kill(t->tid, sig); + + /* increase threads count */ + + count++; + } + + return count; } #else @@ -456,7 +444,7 @@ static void threads_cast_darwinstop(void) if (r != KERN_SUCCESS) vm_abort("thread_get_state failed"); - thread_restartcriticalsection((ucontext_t *) &thread_state); + md_critical_section_restart((ucontext_t *) &thread_state); r = thread_set_state(thread, flavor, (natural_t *) &thread_state, thread_state_count); @@ -506,11 +494,14 @@ static void threads_cast_irixresume(void) void threads_cast_stopworld(void) { #if !defined(__DARWIN__) && !defined(__CYGWIN__) - int count, i; + s4 count, i; #endif lock_stopworld(STOPWORLD_FROM_CLASS_NUMBERING); - pthread_mutex_lock(&threadlistlock); + + /* lock the threads lists */ + + threads_list_lock(); #if defined(__DARWIN__) threads_cast_darwinstop(); @@ -518,17 +509,24 @@ void threads_cast_stopworld(void) /* TODO */ assert(0); #else - count = threads_cast_sendsignals(GC_signum1(), 0); + /* send all threads the suspend signal */ + + count = threads_cast_sendsignals(GC_signum1()); + + /* wait for all threads signaled to suspend */ + for (i = 0; i < count; i++) threads_sem_wait(&suspend_ack); #endif - pthread_mutex_unlock(&threadlistlock); + /* ATTENTION: Don't unlock the threads-lists here so that + non-signaled NEW threads can't change their state and execute + code. */ } + void threads_cast_startworld(void) { - pthread_mutex_lock(&threadlistlock); #if defined(__DARWIN__) threads_cast_darwinresume(); #elif defined(__MIPS__) @@ -537,22 +535,26 @@ void threads_cast_startworld(void) /* TODO */ assert(0); #else - threads_cast_sendsignals(GC_signum2(), -1); + (void) threads_cast_sendsignals(GC_signum2()); #endif - pthread_mutex_unlock(&threadlistlock); + + /* unlock the threads lists */ + + threads_list_unlock(); + unlock_stopworld(); } #if !defined(__DARWIN__) -static void threads_sigsuspend_handler(ucontext_t *ctx) +static void threads_sigsuspend_handler(ucontext_t *_uc) { int sig; sigset_t sigs; /* XXX TWISTI: this is just a quick hack */ #if defined(ENABLE_JIT) - thread_restartcriticalsection(ctx); + md_critical_section_restart(_uc); #endif /* Do as Boehm does. On IRIX a condition variable is used for wake-up @@ -575,20 +577,25 @@ static void threads_sigsuspend_handler(ucontext_t *ctx) #endif } +#endif + + /* This function is called from Boehm GC code. */ -int cacao_suspendhandler(ucontext_t *ctx) +int cacao_suspendhandler(ucontext_t *_uc) { if (stopworldwhere != STOPWORLD_FROM_CLASS_NUMBERING) return 0; - threads_sigsuspend_handler(ctx); + threads_sigsuspend_handler(_uc); return 1; } -#endif #endif /* DISABLE_GC */ +#endif /* 0 */ + + /* threads_set_current_threadobject ******************************************** Set the current thread object. @@ -598,41 +605,70 @@ int cacao_suspendhandler(ucontext_t *ctx) *******************************************************************************/ -static void threads_set_current_threadobject(threadobject *thread) +void threads_set_current_threadobject(threadobject *thread) { #if !defined(HAVE___THREAD) - pthread_setspecific(threads_current_threadobject_key, thread); + if (pthread_setspecific(threads_current_threadobject_key, thread) != 0) + vm_abort("threads_set_current_threadobject: pthread_setspecific failed: %s", strerror(errno)); #else threads_current_threadobject = thread; #endif } -/* threads_init_threadobject ************************************************** +/* threads_impl_thread_new ***************************************************** Initialize implementation fields of a threadobject. IN: - thread............the threadobject + t....the threadobject -******************************************************************************/ +*******************************************************************************/ -static void threads_init_threadobject(threadobject *thread) +void threads_impl_thread_new(threadobject *t) { - thread->tid = pthread_self(); + /* get the pthread id */ - thread->index = 0; + t->tid = pthread_self(); - /* TODO destroy all those things */ - pthread_mutex_init(&(thread->joinmutex), NULL); - pthread_cond_init(&(thread->joincond), NULL); + /* initialize the mutex and the condition */ - pthread_mutex_init(&(thread->waitmutex), NULL); - pthread_cond_init(&(thread->waitcond), NULL); + pthread_mutex_init(&(t->waitmutex), NULL); + pthread_cond_init(&(t->waitcond), NULL); - thread->interrupted = false; - thread->signaled = false; - thread->sleeping = false; +#if defined(ENABLE_DEBUG_FILTER) + /* Initialize filter counters */ + t->filterverbosecallctr[0] = 0; + t->filterverbosecallctr[1] = 0; +#endif + +#if !defined(NDEBUG) + t->tracejavacallindent = 0; + t->tracejavacallcount = 0; +#endif +} + + +/* threads_impl_thread_free **************************************************** + + Cleanup thread stuff. + + IN: + t....the threadobject + +*******************************************************************************/ + +void threads_impl_thread_free(threadobject *t) +{ + /* destroy the mutex and the condition */ + + if (pthread_mutex_destroy(&(t->waitmutex)) != 0) + vm_abort("threads_impl_thread_free: pthread_mutex_destroy failed: %s", + strerror(errno)); + + if (pthread_cond_destroy(&(t->waitcond)) != 0) + vm_abort("threads_impl_thread_free: pthread_cond_destroy failed: %s", + strerror(errno)); } @@ -651,7 +687,7 @@ threadobject *threads_get_current_threadobject(void) } -/* threads_preinit ************************************************************* +/* threads_impl_preinit ******************************************************** Do some early initialization of stuff required. @@ -660,38 +696,86 @@ threadobject *threads_get_current_threadobject(void) *******************************************************************************/ -void threads_preinit(void) +void threads_impl_preinit(void) { - pthread_mutexattr_t mutexattr; - pthread_mutexattr_init(&mutexattr); - pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_RECURSIVE); - pthread_mutex_init(&compiler_mutex, &mutexattr); - pthread_mutexattr_destroy(&mutexattr); - - pthread_mutex_init(&threadlistlock, NULL); pthread_mutex_init(&stopworldlock, NULL); - mainthreadobj = NEW(threadobject); - mainthreadobj->tid = pthread_self(); - mainthreadobj->index = 1; - mainthreadobj->thinlock = lock_pre_compute_thinlock(mainthreadobj->index); - + /* initialize exit mutex and condition (on exit we join all + threads) */ + + pthread_mutex_init(&mutex_join, NULL); + pthread_cond_init(&cond_join, NULL); + + /* initialize the threads-list mutex */ + + pthread_mutex_init(&mutex_threads_list, NULL); + #if !defined(HAVE___THREAD) pthread_key_create(&threads_current_threadobject_key, NULL); #endif - threads_set_current_threadobject(mainthreadobj); - threads_sem_init(&suspend_ack, 0, 0); +/* threads_sem_init(&suspend_ack, 0, 0); */ +} + + +/* threads_list_lock *********************************************************** + + Enter the threads table mutex. + + NOTE: We need this function as we can't use an internal lock for + the threads lists because the thread's lock is initialized in + threads_table_add (when we have the thread index), but we + already need the lock at the entry of the function. + +*******************************************************************************/ + +void threads_list_lock(void) +{ + if (pthread_mutex_lock(&mutex_threads_list) != 0) + vm_abort("threads_list_lock: pthread_mutex_lock failed: %s", + strerror(errno)); +} - /* initialize the threads table */ - threads_table_init(); +/* threads_list_unlock ********************************************************* - /* initialize subsystems */ + Leave the threads list mutex. - lock_init(); +*******************************************************************************/ - critical_init(); +void threads_list_unlock(void) +{ + if (pthread_mutex_unlock(&mutex_threads_list) != 0) + vm_abort("threads_list_unlock: pthread_mutex_unlock failed: %s", + strerror(errno)); +} + + +/* threads_mutex_join_lock ***************************************************** + + Enter the join mutex. + +*******************************************************************************/ + +void threads_mutex_join_lock(void) +{ + if (pthread_mutex_lock(&mutex_join) != 0) + vm_abort("threads_mutex_join_lock: pthread_mutex_lock failed: %s", + strerror(errno)); +} + + +/* threads_mutex_join_unlock *************************************************** + + Leave the join mutex. + +*******************************************************************************/ + +void threads_mutex_join_unlock(void) +{ + if (pthread_mutex_unlock(&mutex_join) != 0) + vm_abort("threads_mutex_join_unlock: pthread_mutex_unlock failed: %s", + strerror(errno)); } @@ -703,31 +787,21 @@ void threads_preinit(void) bool threads_init(void) { - java_lang_String *threadname; - threadobject *tempthread; - java_objectheader *o; + threadobject *mainthread; + java_handle_t *threadname; + java_lang_Thread *t; + java_handle_t *o; #if defined(ENABLE_JAVASE) java_lang_ThreadGroup *threadgroup; methodinfo *m; - java_lang_Thread *t; #endif #if defined(WITH_CLASSPATH_GNU) java_lang_VMThread *vmt; #endif - tempthread = mainthreadobj; - - /* XXX We have to find a new way to free lock records */ - /* with the new locking algorithm. */ - /* lock_record_free_pools(mainthreadobj->ee.lockrecordpools); */ - - /* This is kinda tricky, we grow the java.lang.Thread object so we - can keep the execution environment there. No Thread object must - have been created at an earlier time. */ - - class_java_lang_Thread->instancesize = sizeof(threadobject); + pthread_attr_t attr; /* get methods we need in this file */ @@ -738,48 +812,49 @@ bool threads_init(void) utf_new_char("(Ljava/lang/VMThread;Ljava/lang/String;IZ)V"), class_java_lang_Thread, true); -#else +#elif defined(WITH_CLASSPATH_SUN) + method_thread_init = + class_resolveclassmethod(class_java_lang_Thread, + utf_init, + utf_new_char("(Ljava/lang/String;)V"), + class_java_lang_Thread, + true); +#elif defined(WITH_CLASSPATH_CLDC1_1) method_thread_init = class_resolveclassmethod(class_java_lang_Thread, utf_init, utf_new_char("(Ljava/lang/String;)V"), class_java_lang_Thread, true); +#else +# error unknown classpath configuration #endif if (method_thread_init == NULL) return false; - /* create a java.lang.Thread for the main thread */ - - mainthreadobj = (threadobject *) builtin_new(class_java_lang_Thread); - - if (mainthreadobj == NULL) - return false; - - FREE(tempthread, threadobject); + /* Get the main-thread (NOTE: The main threads is always the first + thread in the list). */ - threads_init_threadobject(mainthreadobj); + mainthread = threads_list_first(); - threads_set_current_threadobject(mainthreadobj); - - lock_init_execution_env(mainthreadobj); + /* create a java.lang.Thread for the main thread */ - mainthreadobj->next = mainthreadobj; - mainthreadobj->prev = mainthreadobj; + t = (java_lang_Thread *) builtin_new(class_java_lang_Thread); - threads_table_add(mainthreadobj); + if (t == NULL) + return false; - /* mark main thread as Java thread */ + /* set the object in the internal data structure */ - mainthreadobj->flags = THREAD_FLAG_JAVA; + mainthread->object = t; #if defined(ENABLE_INTRP) /* create interpreter stack */ if (opt_intrp) { MSET(intrp_main_stack, 0, u1, opt_stacksize); - mainthreadobj->_global_sp = (Cell*) (intrp_main_stack + opt_stacksize); + mainthread->_global_sp = (Cell*) (intrp_main_stack + opt_stacksize); } #endif @@ -792,7 +867,7 @@ bool threads_init(void) native_new_and_init(class_java_lang_ThreadGroup); if (threadgroup == NULL) - throw_exception_exit(); + return false; #endif #if defined(WITH_CLASSPATH_GNU) @@ -801,32 +876,54 @@ bool threads_init(void) vmt = (java_lang_VMThread *) builtin_new(class_java_lang_VMThread); if (vmt == NULL) - throw_exception_exit(); + return false; /* set the thread */ - t = (java_lang_Thread *) mainthreadobj; - vmt->thread = t; + LLNI_field_set_ref(vmt, thread, t); + LLNI_field_set_val(vmt, vmdata, (java_lang_Object *) mainthread); /* call java.lang.Thread.(Ljava/lang/VMThread;Ljava/lang/String;IZ)V */ - o = (java_objectheader *) mainthreadobj; + o = (java_handle_t *) t; (void) vm_call_method(method_thread_init, o, vmt, threadname, NORM_PRIORITY, false); + +#elif defined(WITH_CLASSPATH_SUN) + + /* We trick java.lang.Thread., which sets the priority of + the current thread to the parent's one. */ + + t->priority = NORM_PRIORITY; + + /* Call java.lang.Thread.(Ljava/lang/String;)V */ + + o = (java_object_t *) t; + + (void) vm_call_method(method_thread_init, o, threadname); + #elif defined(WITH_CLASSPATH_CLDC1_1) + + /* set the thread */ + + t->vm_thread = (java_lang_Object *) mainthread; + /* call public Thread(String name) */ - o = (java_objectheader *) mainthreadobj; + o = (java_handle_t *) t; (void) vm_call_method(method_thread_init, o, threadname); +#else +# error unknown classpath configuration #endif - if (*exceptionptr) + if (exceptions_get_exception()) return false; #if defined(ENABLE_JAVASE) - mainthreadobj->o.group = threadgroup; + LLNI_field_set_ref(t, group, threadgroup); +# if defined(WITH_CLASSPATH_GNU) /* add main thread to java.lang.ThreadGroup */ m = class_resolveclassmethod(class_java_lang_ThreadGroup, @@ -835,153 +932,39 @@ bool threads_init(void) class_java_lang_ThreadGroup, true); - o = (java_objectheader *) threadgroup; - t = (java_lang_Thread *) mainthreadobj; + o = (java_handle_t *) threadgroup; (void) vm_call_method(m, o, t); - if (*exceptionptr) + if (exceptions_get_exception()) return false; - +# else +# warning Do not know what to do here +# endif #endif threads_set_thread_priority(pthread_self(), NORM_PRIORITY); /* initialize the thread attribute object */ - if (pthread_attr_init(&threadattr)) { - log_println("pthread_attr_init failed: %s", strerror(errno)); - return false; - } - - pthread_attr_setdetachstate(&threadattr, PTHREAD_CREATE_DETACHED); - - /* everything's ok */ - - return true; -} - - -/* threads_table_init ********************************************************* - - Initialize the global threads table. - -******************************************************************************/ - -static void threads_table_init(void) -{ - s4 size; - s4 i; - - size = THREADS_INITIAL_TABLE_SIZE; - - threads_table.size = size; - threads_table.table = MNEW(threads_table_entry_t, size); - - /* link the entries in a freelist */ - - for (i=0; iindex = index; - thread->thinlock = lock_pre_compute_thinlock(index); - return index; - } + if (pthread_attr_init(&attr) != 0) + vm_abort("threads_init: pthread_attr_init failed: %s", strerror(errno)); - /* we must grow the table */ + if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) != 0) + vm_abort("threads_init: pthread_attr_setdetachstate failed: %s", + strerror(errno)); - oldsize = threads_table.size; - newsize = oldsize * 2; - - threads_table.table = MREALLOC(threads_table.table, threads_table_entry_t, - oldsize, newsize); - threads_table.size = newsize; - - /* link the new entries to a free list */ - - for (i=oldsize; iindex; - - /* put the index into the freelist */ - - threads_table.table[index] = threads_table.table[0]; - threads_table.table[0].nextfree = index; + /* everything's ok */ - /* delete the index in the threadobject to discover bugs */ -#if !defined(NDEBUG) - thread->index = 0; -#endif + return true; } @@ -997,14 +980,14 @@ static void threads_table_remove(threadobject *thread) threads_startup. IN: - t............the argument passed to pthread_create, ie. a pointer to + arg..........the argument passed to pthread_create, ie. a pointer to a startupinfo struct. CAUTION: When the `psem` semaphore is posted, the startupinfo struct becomes invalid! (It is allocated on the stack of threads_start_thread.) ******************************************************************************/ -static void *threads_startup_thread(void *t) +static void *threads_startup_thread(void *arg) { startupinfo *startup; threadobject *thread; @@ -1012,10 +995,9 @@ static void *threads_startup_thread(void *t) java_lang_VMThread *vmt; #endif sem_t *psem; - threadobject *tnext; classinfo *c; methodinfo *m; - java_objectheader *o; + java_handle_t *o; functionptr function; #if defined(ENABLE_INTRP) @@ -1033,41 +1015,33 @@ static void *threads_startup_thread(void *t) /* get passed startupinfo structure and the values in there */ - startup = t; - t = NULL; /* make sure it's not used wrongly */ + startup = arg; thread = startup->thread; function = startup->function; psem = startup->psem; - /* Seems like we've encountered a situation where thread->tid was not set by - * pthread_create. We alleviate this problem by waiting for pthread_create - * to return. */ - threads_sem_wait(startup->psem_first); + /* Seems like we've encountered a situation where thread->tid was + not set by pthread_create. We alleviate this problem by waiting + for pthread_create to return. */ - /* set the thread object */ + threads_sem_wait(startup->psem_first); #if defined(__DARWIN__) thread->mach_thread = mach_thread_self(); #endif - threads_set_current_threadobject(thread); - - /* insert the thread into the threadlist and the threads table */ - pthread_mutex_lock(&threadlistlock); + /* store the internal thread data-structure in the TSD */ - thread->prev = mainthreadobj; - thread->next = tnext = mainthreadobj->next; - mainthreadobj->next = thread; - tnext->prev = thread; + threads_set_current_threadobject(thread); - threads_table_add(thread); + /* set our priority */ - pthread_mutex_unlock(&threadlistlock); + threads_set_thread_priority(thread->tid, LLNI_field_direct(thread->object, priority)); - /* init data structures of this thread */ + /* thread is completely initialized */ - lock_init_execution_env(thread); + threads_thread_state_runnable(thread); /* tell threads_startup_thread that we registered ourselves */ /* CAUTION: *startup becomes invalid with this! */ @@ -1075,10 +1049,6 @@ static void *threads_startup_thread(void *t) startup = NULL; threads_sem_post(psem); - /* set our priority */ - - threads_set_thread_priority(thread->tid, thread->o.priority); - #if defined(ENABLE_INTRP) /* set interpreter stack */ @@ -1093,27 +1063,33 @@ static void *threads_startup_thread(void *t) jvmti_ThreadStartEnd(JVMTI_EVENT_THREAD_START); #endif +#if !defined(NDEBUG) + if (opt_verbosethreads) { + printf("[Starting thread "); + threads_thread_print_info(thread); + printf("]\n"); + } +#endif + /* find and run the Thread.run()V method if no other function was passed */ if (function == NULL) { - /* this is a normal Java thread */ - - thread->flags |= THREAD_FLAG_JAVA; - #if defined(WITH_CLASSPATH_GNU) /* We need to start the run method of java.lang.VMThread. Since this is a final class, we can use the class object directly. */ - c = class_java_lang_VMThread; -#elif defined(WITH_CLASSPATH_CLDC1_1) - c = thread->o.header.vftbl->class; + c = class_java_lang_VMThread; +#elif defined(WITH_CLASSPATH_SUN) || defined(WITH_CLASSPATH_CLDC1_1) + c = thread->object->header.vftbl->class; +#else +# error unknown classpath configuration #endif m = class_resolveclassmethod(c, utf_run, utf_void__void, c, true); if (m == NULL) - throw_exception(); + vm_abort("threads_startup_thread: run() method not found in class"); /* set ThreadMXBean variables */ @@ -1128,20 +1104,20 @@ static void *threads_startup_thread(void *t) #if defined(WITH_CLASSPATH_GNU) /* we need to start the run method of java.lang.VMThread */ - vmt = (java_lang_VMThread *) thread->o.vmThread; - o = (java_objectheader *) vmt; + vmt = (java_lang_VMThread *) LLNI_field_direct(thread->object, vmThread); + o = (java_handle_t *) vmt; -#elif defined(WITH_CLASSPATH_CLDC1_1) - o = (java_objectheader *) thread; +#elif defined(WITH_CLASSPATH_SUN) || defined(WITH_CLASSPATH_CLDC1_1) + o = (java_handle_t *) thread->object; +#else +# error unknown classpath configuration #endif + /* run the thread */ + (void) vm_call_method(m, o); } else { - /* this is an internal thread */ - - thread->flags |= THREAD_FLAG_INTERNAL; - /* set ThreadMXBean variables */ _Jv_jvm->java_lang_management_ThreadMXBean_ThreadCount++; @@ -1157,6 +1133,14 @@ static void *threads_startup_thread(void *t) (function)(); } +#if !defined(NDEBUG) + if (opt_verbosethreads) { + printf("[Stopping thread "); + threads_thread_print_info(thread); + printf("]\n"); + } +#endif + #if defined(ENABLE_JVMTI) /* fire thread end event */ @@ -1164,7 +1148,9 @@ static void *threads_startup_thread(void *t) jvmti_ThreadStartEnd(JVMTI_EVENT_THREAD_END); #endif - threads_detach_thread(thread); + /* We ignore the return value. */ + + (void) threads_detach_thread(thread); /* set ThreadMXBean variables */ @@ -1174,49 +1160,68 @@ static void *threads_startup_thread(void *t) } -/* threads_start_thread ******************************************************** +/* threads_impl_thread_start *************************************************** - Start a thread in the JVM. + Start a thread in the JVM. Both (vm internal and java) thread + objects exist. IN: - thread.......the thread object - function.....function to run in the new thread. NULL means that the - "run" method of the object `t` should be called + thread....the thread object + f.........function to run in the new thread. NULL means that the + "run" method of the object `t` should be called ******************************************************************************/ -void threads_start_thread(threadobject *thread, functionptr function) +void threads_impl_thread_start(threadobject *thread, functionptr f) { sem_t sem; sem_t sem_first; pthread_attr_t attr; startupinfo startup; + int ret; /* fill startupinfo structure passed by pthread_create to * threads_startup_thread */ startup.thread = thread; - startup.function = function; /* maybe we don't call Thread.run()V */ + startup.function = f; /* maybe we don't call Thread.run()V */ startup.psem = &sem; startup.psem_first = &sem_first; threads_sem_init(&sem, 0, 0); threads_sem_init(&sem_first, 0, 0); - /* initialize thread attribute object */ + /* initialize thread attributes */ + + if (pthread_attr_init(&attr) != 0) + vm_abort("threads_impl_thread_start: pthread_attr_init failed: %s", + strerror(errno)); - if (pthread_attr_init(&attr)) - vm_abort("pthread_attr_init failed: %s", strerror(errno)); + if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) != 0) + vm_abort("threads_impl_thread_start: pthread_attr_setdetachstate failed: %s", + strerror(errno)); /* initialize thread stacksize */ if (pthread_attr_setstacksize(&attr, opt_stacksize)) - vm_abort("pthread_attr_setstacksize failed: %s", strerror(errno)); + vm_abort("threads_impl_thread_start: pthread_attr_setstacksize failed: %s", + strerror(errno)); /* create the thread */ - if (pthread_create(&(thread->tid), &attr, threads_startup_thread, &startup)) - vm_abort("pthread_create failed: %s", strerror(errno)); + ret = pthread_create(&(thread->tid), &attr, threads_startup_thread, &startup); + + /* destroy the thread attributes */ + + if (pthread_attr_destroy(&attr) != 0) + vm_abort("threads_impl_thread_start: pthread_attr_destroy failed: %s", + strerror(errno)); + + /* check for pthread_create error */ + + if (ret != 0) + vm_abort("threads_impl_thread_start: pthread_create failed: %s", + strerror(errno)); /* signal that pthread_create has returned, so thread->tid is valid */ @@ -1248,14 +1253,6 @@ void threads_set_thread_priority(pthread_t tid, int priority) struct sched_param schedp; int policy; -#if defined(ENABLE_JAVAME_CLDC1_1) - /* The thread id is zero when a thread is created in Java. The - priority is set later during startup. */ - - if (tid == NULL) - return; -#endif - pthread_getschedparam(tid, &policy, &schedp); schedp.sched_priority = priority; pthread_setschedparam(tid, policy, &schedp); @@ -1272,12 +1269,14 @@ bool threads_attach_current_thread(JavaVMAttachArgs *vm_aargs, bool isdaemon) { threadobject *thread; utf *u; - java_lang_String *s; - java_objectheader *o; + java_handle_t *s; + java_handle_t *o; java_lang_Thread *t; #if defined(ENABLE_JAVASE) java_lang_ThreadGroup *group; + threadobject *mainthread; + classinfo *c; methodinfo *m; #endif @@ -1285,40 +1284,49 @@ bool threads_attach_current_thread(JavaVMAttachArgs *vm_aargs, bool isdaemon) java_lang_VMThread *vmt; #endif - /* create a java.lang.Thread object */ + /* Enter the join-mutex, so if the main-thread is currently + waiting to join all threads, the number of non-daemon threads + is correct. */ - thread = (threadobject *) builtin_new(class_java_lang_Thread); + threads_mutex_join_lock(); - if (thread == NULL) - return false; + /* create internal thread data-structure */ - /* cast for convenience */ + thread = threads_thread_new(); - t = (java_lang_Thread *) thread; + /* thread is a Java thread and running */ - threads_init_threadobject(thread); - threads_set_current_threadobject(thread); - lock_init_execution_env(thread); + thread->flags = THREAD_FLAG_JAVA; - /* insert the thread into the threadlist and the threads table */ + if (isdaemon) + thread->flags |= THREAD_FLAG_DAEMON; - pthread_mutex_lock(&threadlistlock); + /* The thread is flagged and (non-)daemon thread, we can leave the + mutex. */ - thread->prev = mainthreadobj; - thread->next = mainthreadobj->next; - mainthreadobj->next = thread; - thread->next->prev = thread; + threads_mutex_join_unlock(); - threads_table_add(thread); + /* create a java.lang.Thread object */ - pthread_mutex_unlock(&threadlistlock); + t = (java_lang_Thread *) builtin_new(class_java_lang_Thread); - /* mark thread as Java thread */ + /* XXX memory leak!!! */ + if (t == NULL) + return false; - thread->flags = THREAD_FLAG_JAVA; + thread->object = t; - if (isdaemon) - thread->flags |= THREAD_FLAG_DAEMON; + /* thread is completely initialized */ + + threads_thread_state_runnable(thread); + +#if !defined(NDEBUG) + if (opt_verbosethreads) { + printf("[Attaching thread "); + threads_thread_print_info(thread); + printf("]\n"); + } +#endif #if defined(ENABLE_INTRP) /* create interpreter stack */ @@ -1330,16 +1338,30 @@ bool threads_attach_current_thread(JavaVMAttachArgs *vm_aargs, bool isdaemon) #endif #if defined(WITH_CLASSPATH_GNU) + /* create a java.lang.VMThread object */ vmt = (java_lang_VMThread *) builtin_new(class_java_lang_VMThread); + /* XXX memory leak!!! */ if (vmt == NULL) return false; /* set the thread */ - vmt->thread = t; + LLNI_field_set_ref(vmt, thread, t); + LLNI_field_set_val(vmt, vmdata, (java_lang_Object *) thread); + +#elif defined(WITH_CLASSPATH_SUN) + + vm_abort("threads_attach_current_thread: IMPLEMENT ME!"); + +#elif defined(WITH_CLASSPATH_CLDC1_1) + + LLNI_field_set_val(t, vm_thread, (java_lang_Object *) thread); + +#else +# error unknown classpath configuration #endif if (vm_aargs != NULL) { @@ -1351,13 +1373,20 @@ bool threads_attach_current_thread(JavaVMAttachArgs *vm_aargs, bool isdaemon) else { u = utf_null; #if defined(ENABLE_JAVASE) - group = mainthreadobj->o.group; + /* get the main thread */ + + mainthread = threads_list_first(); + group = LLNI_field_direct(mainthread->object, group); #endif } + /* the the thread name */ + s = javastring_new(u); - o = (java_objectheader *) thread; + /* for convenience */ + + o = (java_handle_t *) thread->object; #if defined(WITH_CLASSPATH_GNU) (void) vm_call_method(method_thread_init, o, vmt, s, NORM_PRIORITY, @@ -1366,27 +1395,29 @@ bool threads_attach_current_thread(JavaVMAttachArgs *vm_aargs, bool isdaemon) (void) vm_call_method(method_thread_init, o, s); #endif - if (*exceptionptr) + if (exceptions_get_exception()) return false; #if defined(ENABLE_JAVASE) /* store the thread group in the object */ - thread->o.group = group; + LLNI_field_direct(thread->object, group) = group; /* add thread to given thread-group */ - m = class_resolveclassmethod(group->header.vftbl->class, + LLNI_class_get(group, c); + + m = class_resolveclassmethod(c, utf_addThread, utf_java_lang_Thread__V, class_java_lang_ThreadGroup, true); - o = (java_objectheader *) group; + o = (java_handle_t *) group; (void) vm_call_method(m, o, t); - if (*exceptionptr) + if (exceptions_get_exception()) return false; #endif @@ -1400,100 +1431,130 @@ bool threads_attach_current_thread(JavaVMAttachArgs *vm_aargs, bool isdaemon) *******************************************************************************/ -bool threads_detach_thread(threadobject *thread) +bool threads_detach_thread(threadobject *t) { #if defined(ENABLE_JAVASE) + java_lang_Thread *object; java_lang_ThreadGroup *group; + java_handle_t *e; + java_lang_Object *handler; + classinfo *c; methodinfo *m; - java_objectheader *o; - java_lang_Thread *t; + java_handle_t *o; #endif - /* Allow lock record pools to be used by other threads. They - cannot be deleted so we'd better not waste them. */ +#if defined(ENABLE_JAVASE) + object = t->object; - /* XXX We have to find a new way to free lock records */ - /* with the new locking algorithm. */ - /* lock_record_free_pools(thread->ee.lockrecordpools); */ + group = LLNI_field_direct(object, group); - /* XXX implement uncaught exception stuff (like JamVM does) */ + /* If there's an uncaught exception, call uncaughtException on the + thread's exception handler, or the thread's group if this is + unset. */ -#if defined(ENABLE_JAVASE) - /* remove thread from the thread group */ + e = exceptions_get_and_clear_exception(); + + if (e != NULL) { + /* We use a java_lang_Object here, as it's not trivial to + build the java_lang_Thread_UncaughtExceptionHandler header + file. */ + +# if defined(WITH_CLASSPATH_GNU) + handler = (java_lang_Object *) LLNI_field_direct(object, exceptionHandler); +# elif defined(WITH_CLASSPATH_SUN) + handler = (java_lang_Object *) LLNI_field_direct(object, uncaughtExceptionHandler); +# endif - group = thread->o.group; + if (handler != NULL) { + LLNI_class_get(handler, c); + o = (java_handle_t *) handler; + } + else { + LLNI_class_get(group, c); + o = (java_handle_t *) group; + } + + m = class_resolveclassmethod(c, + utf_uncaughtException, + utf_java_lang_Thread_java_lang_Throwable__V, + NULL, + true); + + if (m == NULL) + return false; + + (void) vm_call_method(m, o, object, e); + + if (exceptions_get_exception()) + return false; + } /* XXX TWISTI: should all threads be in a ThreadGroup? */ + /* Remove thread from the thread group. */ + if (group != NULL) { - m = class_resolveclassmethod(group->header.vftbl->class, + LLNI_class_get(group, c); + +# if defined(WITH_CLASSPATH_GNU) + m = class_resolveclassmethod(c, utf_removeThread, utf_java_lang_Thread__V, class_java_lang_ThreadGroup, true); +# elif defined(WITH_CLASSPATH_SUN) + m = class_resolveclassmethod(c, + utf_remove, + utf_java_lang_Thread__V, + class_java_lang_ThreadGroup, + true); +# else +# error unknown classpath configuration +# endif if (m == NULL) return false; - o = (java_objectheader *) group; - t = (java_lang_Thread *) thread; + o = (java_handle_t *) group; - (void) vm_call_method(m, o, t); + (void) vm_call_method(m, o, object); - if (*exceptionptr) + if (exceptions_get_exception()) return false; } #endif - /* remove thread from thread list and threads table, do this - inside a lock */ + /* thread is terminated */ - pthread_mutex_lock(&threadlistlock); + threads_thread_state_terminated(t); - thread->next->prev = thread->prev; - thread->prev->next = thread->next; +#if !defined(NDEBUG) + if (opt_verbosethreads) { + printf("[Detaching thread "); + threads_thread_print_info(t); + printf("]\n"); + } +#endif - threads_table_remove(thread); + /* Enter the join-mutex before calling threads_thread_free, so + threads_join_all_threads gets the correct number of non-daemon + threads. */ - pthread_mutex_unlock(&threadlistlock); + threads_mutex_join_lock(); - /* reset thread id (lock on joinmutex? TWISTI) */ + /* free the vm internal thread object */ - pthread_mutex_lock(&(thread->joinmutex)); - thread->tid = 0; - pthread_mutex_unlock(&(thread->joinmutex)); + threads_thread_free(t); - /* tell everyone that a thread has finished */ + /* Signal that this thread has finished and leave the mutex. */ - pthread_cond_broadcast(&(thread->joincond)); + pthread_cond_signal(&cond_join); + threads_mutex_join_unlock(); return true; } -/* threads_find_non_daemon_thread ********************************************** - - Helper function used by threads_join_all_threads for finding - non-daemon threads that are still running. - -*******************************************************************************/ - -/* At the end of the program, we wait for all running non-daemon - threads to die. */ - -static threadobject *threads_find_non_daemon_thread(threadobject *thread) -{ - while (thread != mainthreadobj) { - if (!(thread->flags & THREAD_FLAG_DAEMON)) - return thread; - - thread = thread->prev; - } - - return NULL; -} - - /* threads_join_all_threads **************************************************** Join all non-daemon threads. @@ -1502,24 +1563,30 @@ static threadobject *threads_find_non_daemon_thread(threadobject *thread) void threads_join_all_threads(void) { - threadobject *thread; + threadobject *t; - pthread_mutex_lock(&threadlistlock); + /* get current thread */ - while ((thread = threads_find_non_daemon_thread(mainthreadobj->prev)) != NULL) { - pthread_mutex_lock(&(thread->joinmutex)); + t = THREADOBJECT; - pthread_mutex_unlock(&threadlistlock); + /* this thread is waiting for all non-daemon threads to exit */ - while (thread->tid) - pthread_cond_wait(&(thread->joincond), &(thread->joinmutex)); + threads_thread_state_waiting(t); - pthread_mutex_unlock(&(thread->joinmutex)); + /* enter join mutex */ - pthread_mutex_lock(&threadlistlock); - } + threads_mutex_join_lock(); + + /* Wait for condition as long as we have non-daemon threads. We + compare against 1 because the current (main thread) is also a + non-daemon thread. */ - pthread_mutex_unlock(&threadlistlock); + while (threads_list_get_non_daemons() > 1) + pthread_cond_wait(&cond_join, &mutex_join); + + /* leave join mutex */ + + threads_mutex_join_unlock(); } @@ -1615,14 +1682,23 @@ static bool threads_wait_with_timeout(threadobject *thread, while (!thread->interrupted && !thread->signaled && threads_current_time_is_earlier_than(wakeupTime)) { + threads_thread_state_timed_waiting(thread); + pthread_cond_timedwait(&thread->waitcond, &thread->waitmutex, wakeupTime); + + threads_thread_state_runnable(thread); } } else { /* no timeout */ - while (!thread->interrupted && !thread->signaled) + while (!thread->interrupted && !thread->signaled) { + threads_thread_state_waiting(thread); + pthread_cond_wait(&thread->waitcond, &thread->waitmutex); + + threads_thread_state_runnable(thread); + } } /* check if we were interrupted */ @@ -1820,107 +1896,6 @@ void threads_yield(void) } -/* threads_dump **************************************************************** - - Dumps info for all threads running in the JVM. This function is - called when SIGQUIT (-\) is sent to CACAO. - -*******************************************************************************/ - -void threads_dump(void) -{ - threadobject *thread; - java_lang_Thread *t; - utf *name; - - thread = mainthreadobj; - - /* XXX we should stop the world here */ - - printf("Full thread dump CACAO "VERSION":\n"); - - /* iterate over all started threads */ - - do { - /* get thread object */ - - t = (java_lang_Thread *) thread; - - /* the thread may be currently in initalization, don't print it */ - - if (t != NULL) { - /* get thread name */ - -#if defined(ENABLE_JAVASE) - name = javastring_toutf(t->name, false); -#elif defined(ENABLE_JAVAME_CLDC1_1) - name = t->name; -#endif - - printf("\n\""); - utf_display_printable_ascii(name); - printf("\" "); - - if (thread->flags & THREAD_FLAG_DAEMON) - printf("daemon "); - -#if SIZEOF_VOID_P == 8 - printf("prio=%d tid=0x%016lx\n", t->priority, (ptrint) thread->tid); -#else - printf("prio=%d tid=0x%08lx\n", t->priority, (ptrint) thread->tid); -#endif - - /* dump trace of thread */ - - stacktrace_dump_trace(thread); - } - - thread = thread->next; - } while ((thread != NULL) && (thread != mainthreadobj)); -} - - -/* threads_table_dump ********************************************************* - - Dump the threads table for debugging purposes. - - IN: - file..............stream to write to - -******************************************************************************/ - -#if !defined(NDEBUG) && 0 -static void threads_table_dump(FILE *file) -{ - s4 i; - s4 size; - ptrint index; - - pthread_mutex_lock(&threadlistlock); - - size = threads_table.size; - - fprintf(file, "======== THREADS TABLE (size %d) ========\n", size); - - for (i=0; i