* Removed all Id tags.
[cacao.git] / src / threads / native / threads.c
index 47053cfeebb42918c9b99c4edeb1a57283db1ce8..a2dd4de09d22b0081ddf883e0b0ec19c7e9a0691 100644 (file)
@@ -1,6 +1,6 @@
 /* src/threads/native/threads.c - native threads support
 
-   Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
+   Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel,
    C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
    E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
    J. Wenninger, Institut f. Computersprachen - TU Wien
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
 
-   Contact: cacao@cacaojvm.org
-
-   Authors: Stefan Ring
-            Christian Thalinger
-            Edwin Steiner
-
-   $Id: threads.c 6251 2006-12-27 23:15:56Z twisti $
-
 */
 
 
 
 #include "mm/gc-common.h"
 #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"
 #include "native/include/java_lang_Throwable.h"
 #include "native/include/java_lang_Thread.h"
 
 # 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"
 #include "vm/exceptions.h"
 #include "vm/global.h"
-#include "vm/loader.h"
-#include "vm/options.h"
 #include "vm/stringlocal.h"
 #include "vm/vm.h"
+
 #include "vm/jit/asmpart.h"
 
+#include "vmcore/options.h"
+
+#if defined(ENABLE_STATISTICS)
+# include "vmcore/statistics.h"
+#endif
+
 #if !defined(__DARWIN__)
 # if defined(__LINUX__)
 #  define GC_LINUX_THREADS
@@ -183,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 *****************************************************************
 
@@ -204,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                                    */
@@ -231,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;
@@ -254,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)
@@ -344,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.
@@ -381,7 +354,7 @@ void compiler_unlock(void)
 void lock_stopworld(int where)
 {
        pthread_mutex_lock(&stopworldlock);
-       stopworldwhere = where;
+/*     stopworldwhere = where; */
 }
 
 
@@ -393,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;
+
+       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 */
 
-       return count - 1;
+               pthread_kill(t->tid, sig);
+
+               /* increase threads count */
+
+               count++;
+       }
+
+       return count;
 }
 
 #else
@@ -454,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);
@@ -504,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();
@@ -516,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__)
@@ -535,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
@@ -573,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.
@@ -596,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));
 }
 
 
@@ -649,7 +687,7 @@ threadobject *threads_get_current_threadobject(void)
 }
 
 
-/* threads_preinit *************************************************************
+/* threads_impl_preinit ********************************************************
 
    Do some early initialization of stuff required.
 
@@ -658,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();
+*******************************************************************************/
+
+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));
+}
 
-       critical_init();
+
+/* 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));
 }
 
 
@@ -701,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_JAVSE)
+#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 */
 
@@ -736,61 +812,62 @@ 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 */
+       /* Get the main-thread (NOTE: The main threads is always the first
+          thread in the list). */
 
-       mainthreadobj = (threadobject *) builtin_new(class_java_lang_Thread);
+       mainthread = threads_list_first();
 
-       if (mainthreadobj == NULL)
-               return false;
-
-       FREE(tempthread, threadobject);
-
-       threads_init_threadobject(mainthreadobj);
-
-       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
 
        threadname = javastring_new(utf_new_char("main"));
 
-#if defined(ENABLE_JAVSE)
+#if defined(ENABLE_JAVASE)
        /* allocate and init ThreadGroup */
 
        threadgroup = (java_lang_ThreadGroup *)
                native_new_and_init(class_java_lang_ThreadGroup);
 
        if (threadgroup == NULL)
-               throw_exception_exit();
+               return false;
 #endif
 
 #if defined(WITH_CLASSPATH_GNU)
@@ -799,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.<init>(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.<init>, which sets the priority of
+          the current thread to the parent's one. */
+
+       t->priority = NORM_PRIORITY;
+
+       /* Call java.lang.Thread.<init>(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,
@@ -833,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; i<size; ++i) {
-               threads_table.table[i].nextfree = i+1;
-       }
-
-       /* terminate the freelist */
-
-       threads_table.table[size-1].nextfree = 0; /* index 0 is never free */
-}
-
-
-/* threads_table_add **********************************************************
-
-   Add a thread to the global threads table. The index is entered in the
-   threadobject. The thinlock value for the thread is pre-computed.
-
-   IN:
-      thread............the thread to add
-
-   RETURN VALUE:
-      The table index for the newly added thread. This value has also been
-         entered in the threadobject.
-
-   PRE-CONDITION:
-      The caller must hold the threadlistlock!
-
-******************************************************************************/
-
-static s4 threads_table_add(threadobject *thread)
-{
-       s4 index;
-       s4 oldsize;
-       s4 newsize;
-       s4 i;
-
-       /* table[0] serves as the head of the freelist */
-
-       index = threads_table.table[0].nextfree;
+       if (pthread_attr_init(&attr) != 0)
+               vm_abort("threads_init: pthread_attr_init failed: %s", strerror(errno));
 
-       /* if we got a free index, use it */
+       if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) != 0)
+               vm_abort("threads_init: pthread_attr_setdetachstate failed: %s",
+                                strerror(errno));
 
-       if (index) {
-got_an_index:
-               threads_table.table[0].nextfree = threads_table.table[index].nextfree;
-               threads_table.table[index].thread = thread;
-               thread->index = index;
-               thread->thinlock = lock_pre_compute_thinlock(index);
-               return index;
-       }
-
-       /* we must grow the table */
-
-       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; i<newsize; ++i) {
-               threads_table.table[i].nextfree = i+1;
+#if !defined(NDEBUG)
+       if (opt_verbosethreads) {
+               printf("[Starting thread ");
+               threads_thread_print_info(mainthread);
+               printf("]\n");
        }
+#endif
 
-       /* terminate the freelist */
-
-       threads_table.table[newsize-1].nextfree = 0; /* index 0 is never free */
-
-       /* use the first of the new entries */
-
-       index = oldsize;
-       goto got_an_index;
-}
-
-
-/* threads_table_remove *******************************************************
-
-   Remove a thread from the global threads table.
-
-   IN:
-      thread............the thread to remove
-
-   PRE-CONDITION:
-      The caller must hold the threadlistlock!
-
-******************************************************************************/
-
-static void threads_table_remove(threadobject *thread)
-{
-       s4 index;
-
-       index = thread->index;
-
-       /* 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;
 }
 
 
@@ -995,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;
@@ -1010,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)
@@ -1031,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 */
+       /* store the internal thread data-structure in the TSD */
 
-       pthread_mutex_lock(&threadlistlock);
-
-       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!             */
@@ -1073,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 */
 
@@ -1091,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 */
 
@@ -1126,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++;
@@ -1155,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 */
 
@@ -1162,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 */
 
@@ -1172,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 */
 
@@ -1246,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);
@@ -1270,53 +1269,64 @@ bool threads_attach_current_thread(JavaVMAttachArgs *vm_aargs, bool isdaemon)
 {
        threadobject          *thread;
        utf                   *u;
-       java_lang_String      *s;
-       methodinfo            *m;
-       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
 
 #if defined(WITH_CLASSPATH_GNU)
        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;
+
+       if (isdaemon)
+               thread->flags |= THREAD_FLAG_DAEMON;
+
+       /* The thread is flagged and (non-)daemon thread, we can leave the
+          mutex. */
 
-       /* insert the thread into the threadlist and the threads table */
+       threads_mutex_join_unlock();
 
-       pthread_mutex_lock(&threadlistlock);
+       /* create a java.lang.Thread object */
 
-       thread->prev        = mainthreadobj;
-       thread->next        = mainthreadobj->next;
-       mainthreadobj->next = thread;
-       thread->next->prev  = thread;
+       t = (java_lang_Thread *) builtin_new(class_java_lang_Thread);
 
-       threads_table_add(thread);
+       /* XXX memory leak!!! */
+       if (t == NULL)
+               return false;
 
-       pthread_mutex_unlock(&threadlistlock);
+       thread->object = t;
 
-       /* mark thread as Java thread */
+       /* thread is completely initialized */
 
-       thread->flags = THREAD_FLAG_JAVA;
+       threads_thread_state_runnable(thread);
 
-       if (isdaemon)
-               thread->flags |= THREAD_FLAG_DAEMON;
+#if !defined(NDEBUG)
+       if (opt_verbosethreads) {
+               printf("[Attaching thread ");
+               threads_thread_print_info(thread);
+               printf("]\n");
+       }
+#endif
 
 #if defined(ENABLE_INTRP)
        /* create interpreter stack */
@@ -1328,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) {
@@ -1349,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,
@@ -1364,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
 
@@ -1398,101 +1431,130 @@ bool threads_attach_current_thread(JavaVMAttachArgs *vm_aargs, bool isdaemon)
 
 *******************************************************************************/
 
-bool threads_detach_thread(threadobject *thread)
+bool threads_detach_thread(threadobject *t)
 {
-       methodinfo            *m;
-       java_objectheader     *o;
-       java_lang_Thread      *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_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;
+
+       group = LLNI_field_direct(object, group);
 
-       /* XXX We have to find a new way to free lock records */
-       /*     with the new locking algorithm.                */
-       /* lock_record_free_pools(thread->ee.lockrecordpools); */
+    /* If there's an uncaught exception, call uncaughtException on the
+       thread's exception handler, or the thread's group if this is
+       unset. */
 
-       /* XXX implement uncaught exception stuff (like JamVM does) */
+       e = exceptions_get_and_clear_exception();
 
-#if defined(ENABLE_JAVASE)
-       /* remove thread from the thread group */
+    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
+
+               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;
 
-       group = thread->o.group;
+               (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.
@@ -1501,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. */
+
+       while (threads_list_get_non_daemons() > 1)
+               pthread_cond_wait(&cond_join, &mutex_join);
 
-       pthread_mutex_unlock(&threadlistlock);
+       /* leave join mutex */
+
+       threads_mutex_join_unlock();
 }
 
 
@@ -1614,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 */
@@ -1803,7 +1880,7 @@ void threads_sleep(s8 millis, s4 nanos)
        wasinterrupted = threads_wait_with_timeout(thread, &wakeupTime);
 
        if (wasinterrupted)
-               *exceptionptr = new_exception(string_java_lang_InterruptedException);
+               exceptions_throw_interruptedexception();
 }
 
 
@@ -1819,107 +1896,6 @@ void threads_yield(void)
 }
 
 
-/* threads_dump ****************************************************************
-
-   Dumps info for all threads running in the JVM. This function is
-   called when SIGQUIT (<ctrl>-\) 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, (long) thread->tid);
-#else
-                       printf("prio=%d tid=0x%08lx\n", t->priority, (long) 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<size; ++i) {
-               index = threads_table.table[i].nextfree;
-
-               fprintf(file, "%4d: ", i);
-
-               if (index < size) {
-                       fprintf(file, "free, nextfree = %d\n", (int) index);
-               }
-               else {
-                       fprintf(file, "thread %p\n", (void*) threads_table.table[i].thread);
-               }
-       }
-
-       fprintf(file, "======== END OF THREADS TABLE ========\n");
-
-       pthread_mutex_unlock(&threadlistlock);
-}
-#endif
-
 /*
  * These are local overrides for various environment variables in Emacs.
  * Please do not remove this and leave it at the end of the file, where