* Removed all Id tags.
[cacao.git] / src / threads / native / threads.c
index 39e15de9c2b73a6ef7a12b717982b59be47299eb..a2dd4de09d22b0081ddf883e0b0ec19c7e9a0691 100644 (file)
@@ -22,8 +22,6 @@
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
 
-   $Id: threads.c 7963 2007-05-24 10:21:16Z 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"
@@ -236,6 +235,11 @@ static pthread_mutex_t stopworldlock;
 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;
@@ -247,6 +251,8 @@ static pthread_mutex_t suspend_ack_lock = PTHREAD_MUTEX_INITIALIZER;
 static pthread_cond_t suspend_cond = PTHREAD_COND_INITIALIZER;
 #endif
 
+#endif /* 0 */
+
 /* mutexes used by the fake atomic instructions                               */
 #if defined(USE_FAKE_ATOMIC_INSTRUCTIONS)
 pthread_mutex_t _atomic_add_lock = PTHREAD_MUTEX_INITIALIZER;
@@ -348,7 +354,7 @@ void threads_sem_post(sem_t *sem)
 void lock_stopworld(int where)
 {
        pthread_mutex_lock(&stopworldlock);
-       stopworldwhere = where;
+/*     stopworldwhere = where; */
 }
 
 
@@ -360,10 +366,15 @@ 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 s4 threads_cast_sendsignals(s4 sig)
@@ -566,6 +577,9 @@ static void threads_sigsuspend_handler(ucontext_t *_uc)
 #endif
 }
 
+#endif
+
+
 /* This function is called from Boehm GC code. */
 
 int cacao_suspendhandler(ucontext_t *_uc)
@@ -576,10 +590,11 @@ int cacao_suspendhandler(ucontext_t *_uc)
        threads_sigsuspend_handler(_uc);
        return 1;
 }
-#endif
 
 #endif /* DISABLE_GC */
 
+#endif /* 0 */
+
 
 /* threads_set_current_threadobject ********************************************
 
@@ -620,6 +635,17 @@ void threads_impl_thread_new(threadobject *t)
 
        pthread_mutex_init(&(t->waitmutex), NULL);
        pthread_cond_init(&(t->waitcond), NULL);
+
+#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
 }
 
 
@@ -680,23 +706,15 @@ void threads_impl_preinit(void)
        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_sem_init(&suspend_ack, 0, 0);
-}
-
-
-/* threads_table_lock **********************************************************
-
-   Initialize threads table mutex.
-
-*******************************************************************************/
-
-void threads_impl_table_init(void)
-{
-       pthread_mutex_init(&mutex_threads_list, NULL);
+/*     threads_sem_init(&suspend_ack, 0, 0); */
 }
 
 
@@ -714,7 +732,7 @@ void threads_impl_table_init(void)
 void threads_list_lock(void)
 {
        if (pthread_mutex_lock(&mutex_threads_list) != 0)
-               vm_abort("threads_table_lock: pthread_mutex_lock failed: %s",
+               vm_abort("threads_list_lock: pthread_mutex_lock failed: %s",
                                 strerror(errno));
 }
 
@@ -728,7 +746,35 @@ void threads_list_lock(void)
 void threads_list_unlock(void)
 {
        if (pthread_mutex_unlock(&mutex_threads_list) != 0)
-               vm_abort("threads_table_unlock: pthread_mutex_unlock failed: %s",
+               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));
 }
 
@@ -741,10 +787,10 @@ void threads_list_unlock(void)
 
 bool threads_init(void)
 {
-       threadobject          *mainthread;
-       java_objectheader     *threadname;
-       java_lang_Thread      *t;
-       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;
@@ -766,13 +812,22 @@ 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)
@@ -825,32 +880,50 @@ bool threads_init(void)
 
        /* set the thread */
 
-       vmt->thread = t;
-       vmt->vmdata = (java_lang_Object *) mainthread;
+       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 *) t;
+       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 *) t;
+       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)
-       t->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,
@@ -859,12 +932,15 @@ bool threads_init(void)
                                                                 class_java_lang_ThreadGroup,
                                                                 true);
 
-       o = (java_objectheader *) threadgroup;
+       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);
@@ -921,7 +997,7 @@ static void *threads_startup_thread(void *arg)
        sem_t              *psem;
        classinfo          *c;
        methodinfo         *m;
-       java_objectheader  *o;
+       java_handle_t      *o;
        functionptr         function;
 
 #if defined(ENABLE_INTRP)
@@ -961,7 +1037,7 @@ static void *threads_startup_thread(void *arg)
 
        /* set our priority */
 
-       threads_set_thread_priority(thread->tid, thread->object->priority);
+       threads_set_thread_priority(thread->tid, LLNI_field_direct(thread->object, priority));
 
        /* thread is completely initialized */
 
@@ -1003,9 +1079,11 @@ static void *threads_startup_thread(void *arg)
                   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->object->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);
@@ -1026,11 +1104,13 @@ static void *threads_startup_thread(void *arg)
 #if defined(WITH_CLASSPATH_GNU)
                /* we need to start the run method of java.lang.VMThread */
 
-               vmt = (java_lang_VMThread *) thread->object->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->object;
+#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 */
@@ -1068,8 +1148,9 @@ static void *threads_startup_thread(void *arg)
                jvmti_ThreadStartEnd(JVMTI_EVENT_THREAD_END);
 #endif
 
-       if (!threads_detach_thread(thread))
-               vm_abort("threads_startup_thread: threads_detach_thread failed");
+       /* We ignore the return value. */
+
+       (void) threads_detach_thread(thread);
 
        /* set ThreadMXBean variables */
 
@@ -1188,13 +1269,14 @@ bool threads_attach_current_thread(JavaVMAttachArgs *vm_aargs, bool isdaemon)
 {
        threadobject          *thread;
        utf                   *u;
-       java_objectheader     *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
 
@@ -1202,26 +1284,38 @@ bool threads_attach_current_thread(JavaVMAttachArgs *vm_aargs, bool isdaemon)
        java_lang_VMThread    *vmt;
 #endif
 
+       /* Enter the join-mutex, so if the main-thread is currently
+          waiting to join all threads, the number of non-daemon threads
+          is correct. */
+
+       threads_mutex_join_lock();
+
        /* create internal thread data-structure */
 
        thread = threads_thread_new();
 
+       /* thread is a Java thread and running */
+
+       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. */
+
+       threads_mutex_join_unlock();
+
        /* create a java.lang.Thread object */
 
        t = (java_lang_Thread *) builtin_new(class_java_lang_Thread);
 
+       /* XXX memory leak!!! */
        if (t == NULL)
                return false;
 
        thread->object = t;
 
-       /* thread is a Java thread and running */
-
-       thread->flags = THREAD_FLAG_JAVA;
-
-       if (isdaemon)
-               thread->flags |= THREAD_FLAG_DAEMON;
-
        /* thread is completely initialized */
 
        threads_thread_state_runnable(thread);
@@ -1244,19 +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;
-       vmt->vmdata = (java_lang_Object *) thread;
+       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)
-       t->vm_thread = (java_lang_Object *) thread;
+
+       LLNI_field_set_val(t, vm_thread, (java_lang_Object *) thread);
+
+#else
+# error unknown classpath configuration
 #endif
 
        if (vm_aargs != NULL) {
@@ -1271,7 +1376,7 @@ bool threads_attach_current_thread(JavaVMAttachArgs *vm_aargs, bool isdaemon)
                /* get the main thread */
 
                mainthread = threads_list_first();
-               group = mainthread->object->group;
+               group = LLNI_field_direct(mainthread->object, group);
 #endif
        }
 
@@ -1281,7 +1386,7 @@ bool threads_attach_current_thread(JavaVMAttachArgs *vm_aargs, bool isdaemon)
 
        /* for convenience */
 
-       o = (java_objectheader *) thread->object;
+       o = (java_handle_t *) thread->object;
 
 #if defined(WITH_CLASSPATH_GNU)
        (void) vm_call_method(method_thread_init, o, vmt, s, NORM_PRIORITY,
@@ -1290,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->object->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
 
@@ -1324,65 +1431,125 @@ 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
 
-       /* XXX implement uncaught exception stuff (like JamVM does) */
-
 #if defined(ENABLE_JAVASE)
-       /* remove thread from the thread group */
+       object = t->object;
+
+       group = LLNI_field_direct(object, group);
+
+    /* If there's an uncaught exception, call uncaughtException on the
+       thread's exception handler, or the thread's group if this is
+       unset. */
+
+       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
+
+               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);
 
-       group = thread->object->group;
+               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 = thread->object;
+               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
 
        /* thread is terminated */
 
-       threads_thread_state_terminated(thread);
+       threads_thread_state_terminated(t);
 
 #if !defined(NDEBUG)
        if (opt_verbosethreads) {
                printf("[Detaching thread ");
-               threads_thread_print_info(thread);
+               threads_thread_print_info(t);
                printf("]\n");
        }
 #endif
 
-       /* signal that this thread has finished */
+       /* Enter the join-mutex before calling threads_thread_free, so
+          threads_join_all_threads gets the correct number of non-daemon
+          threads. */
 
-       pthread_mutex_lock(&mutex_join);
-       pthread_cond_signal(&cond_join);
-       pthread_mutex_unlock(&mutex_join);
+       threads_mutex_join_lock();
 
        /* free the vm internal thread object */
 
-       threads_thread_free(thread);
+       threads_thread_free(t);
+
+       /* Signal that this thread has finished and leave the mutex. */
+
+       pthread_cond_signal(&cond_join);
+       threads_mutex_join_unlock();
 
        return true;
 }
@@ -1408,7 +1575,7 @@ void threads_join_all_threads(void)
 
        /* enter join mutex */
 
-       pthread_mutex_lock(&mutex_join);
+       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
@@ -1419,7 +1586,7 @@ void threads_join_all_threads(void)
 
        /* leave join mutex */
 
-       pthread_mutex_unlock(&mutex_join);
+       threads_mutex_join_unlock();
 }