* src/toolbox/logging.h: Updated copyright.
[cacao.git] / src / threads / thread.c
index 4795898f1fe390fbfc3df8a37adf84492f1e04fe..c857e007d6ff3ab6db089db4c76c790e5d6f9443 100644 (file)
 
 #include "mm/memory.h"
 
+#if defined(ENABLE_GC_BOEHM)
+/* We need to include Boehm's gc.h here for GC_register_my_thread and
+   friends. */
+# include "mm/boehm-gc/include/gc.h"
+#endif
+
 #include "native/jni.h"
 #include "native/llni.h"
 #include "native/native.h"
 # include "native/include/java_lang_ThreadGroup.h"
 #endif
 
-#if defined(WITH_CLASSPATH_GNU)
+#if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
 # include "native/include/java_lang_VMThread.h"
 #endif
 
-#include "threads/critical.h"
 #include "threads/lock-common.h"
 #include "threads/threadlist.h"
 #include "threads/thread.h"
 #include "vm/builtin.h"
 #include "vm/exceptions.h"
 #include "vm/stringlocal.h"
-#include "vm/vm.h"
+#include "vm/vm.hpp"
 
-#include "vm/jit/stacktrace.h"
+#include "vm/jit/stacktrace.hpp"
 
 #include "vmcore/class.h"
+#include "vmcore/globals.hpp"
 #include "vmcore/method.h"
 #include "vmcore/options.h"
 
@@ -148,6 +154,12 @@ void threads_preinit(void)
 
        mainthread = thread_new();
 
+       /* The main thread should always have index 1. */
+
+       if (mainthread->index != 1)
+               vm_abort("threads_preinit: main thread index not 1: %d != 1",
+                                mainthread->index);
+
        /* thread is a Java thread and running */
 
        mainthread->flags |= THREAD_FLAG_JAVA;
@@ -175,7 +187,7 @@ void threads_init(void)
 
        /* Cache the java.lang.Thread initialization method. */
 
-#if defined(WITH_CLASSPATH_GNU)
+#if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
 
        thread_method_init =
                class_resolveclassmethod(class_java_lang_Thread,
@@ -184,7 +196,7 @@ void threads_init(void)
                                                                 class_java_lang_Thread,
                                                                 true);
 
-#elif defined(WITH_CLASSPATH_SUN)
+#elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
 
        thread_method_init =
                class_resolveclassmethod(class_java_lang_Thread,
@@ -193,7 +205,7 @@ void threads_init(void)
                                                                 class_java_lang_Thread,
                                                                 true);
 
-#elif defined(WITH_CLASSPATH_CLDC1_1)
+#elif defined(WITH_JAVA_RUNTIME_LIBRARY_CLDC1_1)
 
        thread_method_init =
                class_resolveclassmethod(class_java_lang_Thread,
@@ -233,7 +245,7 @@ static bool thread_create_object(threadobject *t, java_handle_t *name, java_hand
        java_handle_t    *o;
        java_lang_Thread *to;
 
-#if defined(WITH_CLASSPATH_GNU)
+#if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
        java_lang_VMThread    *vmto;
        classinfo             *c;
        methodinfo            *m;
@@ -254,7 +266,7 @@ static bool thread_create_object(threadobject *t, java_handle_t *name, java_hand
 
        thread_set_object(t, (java_handle_t *) to);
 
-#if defined(WITH_CLASSPATH_GNU)
+#if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
 
        /* Create a java.lang.VMThread Java object. */
 
@@ -304,7 +316,7 @@ static bool thread_create_object(threadobject *t, java_handle_t *name, java_hand
        if (exceptions_get_exception())
                return false;
 
-#elif defined(WITH_CLASSPATH_SUN)
+#elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
 
        /* OpenJDK's java.lang.Thread does not have a VMThread field in
           the class.  Nothing to do here. */
@@ -323,7 +335,7 @@ static bool thread_create_object(threadobject *t, java_handle_t *name, java_hand
        if (exceptions_get_exception())
                return false;
 
-#elif defined(WITH_CLASSPATH_CLDC1_1)
+#elif defined(WITH_JAVA_RUNTIME_LIBRARY_CLDC1_1)
 
        /* Set the thread data-structure in the Java thread object. */
 
@@ -363,7 +375,7 @@ static bool thread_create_object(threadobject *t, java_handle_t *name, java_hand
 static void thread_create_initial_threadgroups(void)
 {
 #if defined(ENABLE_JAVASE)
-# if defined(WITH_CLASSPATH_GNU)
+# if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
 
        /* Allocate and initialize the main thread group. */
 
@@ -376,7 +388,7 @@ static void thread_create_initial_threadgroups(void)
 
        threadgroup_system = threadgroup_main;
 
-# elif defined(WITH_CLASSPATH_SUN)
+# elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
 
        java_handle_t *name;
        methodinfo    *m;
@@ -651,7 +663,7 @@ void threads_thread_start(java_handle_t *object)
 {
        java_lang_Thread   *to;
        threadobject       *t;
-#if defined(WITH_CLASSPATH_GNU)
+#if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
        java_lang_VMThread *vmto;
 #endif
 
@@ -687,7 +699,7 @@ void threads_thread_start(java_handle_t *object)
 
        thread_set_object(t, object);
 
-#if defined(WITH_CLASSPATH_GNU)
+#if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
 
        /* Get the java.lang.VMThread object and do some sanity checks. */
 
@@ -698,11 +710,11 @@ void threads_thread_start(java_handle_t *object)
 
        LLNI_field_set_val(vmto, vmdata, (java_lang_Object *) t);
 
-#elif defined(WITH_CLASSPATH_SUN)
+#elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
 
        /* Nothing to do. */
 
-#elif defined(WITH_CLASSPATH_CLDC1_1)
+#elif defined(WITH_JAVA_RUNTIME_LIBRARY_CLDC1_1)
 
        LLNI_field_set_val(to, vm_thread, (java_lang_Object *) t);
 
@@ -717,13 +729,16 @@ void threads_thread_start(java_handle_t *object)
 }
 
 
-/* threads_attach_current_thread ***********************************************
-
-   Attaches the current thread to the VM.  Used in JNI.
-
-*******************************************************************************/
-
-bool threads_attach_current_thread(JavaVMAttachArgs *vm_aargs, bool isdaemon)
+/**
+ * Attaches the current thread to the VM.
+ *
+ * @param vm_aargs Attach arguments.
+ * @param isdaemon true if the attached thread should be a daemon
+ *                 thread.
+ *
+ * @return true on success, false otherwise.
+ */
+bool thread_attach_current_thread(JavaVMAttachArgs *vm_aargs, bool isdaemon)
 {
        bool           result;
        threadobject  *t;
@@ -756,6 +771,10 @@ bool threads_attach_current_thread(JavaVMAttachArgs *vm_aargs, bool isdaemon)
        if (isdaemon)
                t->flags |= THREAD_FLAG_DAEMON;
 
+       /* Store the internal thread data-structure in the TSD. */
+
+       thread_set_current(t);
+
        /* The thread is flagged and (non-)daemon thread, we can leave the
           mutex. */
 
@@ -779,7 +798,9 @@ bool threads_attach_current_thread(JavaVMAttachArgs *vm_aargs, bool isdaemon)
 
        if (vm_aargs != NULL)
                group = (java_handle_t *) vm_aargs->group;
-               
+       else
+               group = NULL;
+
        /* If no threadgroup was given, use the main threadgroup. */
 
        if (group == NULL)
@@ -802,7 +823,82 @@ bool threads_attach_current_thread(JavaVMAttachArgs *vm_aargs, bool isdaemon)
 
        /* The thread is completely initialized. */
 
-       threads_thread_state_runnable(t);
+       thread_set_state_runnable(t);
+
+       return true;
+}
+
+
+/**
+ * Attaches the current external thread to the VM.  This function is
+ * called by JNI's AttachCurrentThread.
+ *
+ * @param vm_aargs Attach arguments.
+ * @param isdaemon true if the attached thread should be a daemon
+ *                 thread.
+ *
+ * @return true on success, false otherwise.
+ */
+bool thread_attach_current_external_thread(JavaVMAttachArgs *vm_aargs, bool isdaemon)
+{
+       int result;
+
+#if defined(ENABLE_GC_BOEHM)
+       struct GC_stack_base sb;
+#endif
+
+#if defined(ENABLE_GC_BOEHM)
+       /* Register the thread with Boehm-GC.  This must happen before the
+          thread allocates any memory from the GC heap.*/
+
+       result = GC_get_stack_base(&sb);
+
+       if (result != GC_SUCCESS)
+               vm_abort("threads_attach_current_thread: GC_get_stack_base failed");
+
+       GC_register_my_thread(&sb);
+#endif
+
+       result = thread_attach_current_thread(vm_aargs, isdaemon);
+
+       if (result == false) {
+#if defined(ENABLE_GC_BOEHM)
+               /* Unregister the thread. */
+
+               GC_unregister_my_thread();
+#endif
+
+               return false;
+       }
+
+       return true;
+}
+
+
+/**
+ * Detaches the current external thread from the VM.  This function is
+ * called by JNI's DetachCurrentThread.
+ *
+ * @return true on success, false otherwise.
+ */
+bool thread_detach_current_external_thread(void)
+{
+       int result;
+
+       result = thread_detach_current_thread();
+
+       if (result == false)
+               return false;
+
+#if defined(ENABLE_GC_BOEHM)
+       /* Unregister the thread with Boehm-GC.  This must happen after
+          the thread allocates any memory from the GC heap. */
+
+       /* Don't detach the main thread.  This is a workaround for
+          OpenJDK's java binary. */
+       if (thread_get_current()->index != 1)
+               GC_unregister_my_thread();
+#endif
 
        return true;
 }
@@ -822,9 +918,9 @@ void thread_fprint_name(threadobject *t, FILE *stream)
 {
        java_lang_Thread *to;
 
-#if defined(WITH_CLASSPATH_GNU)
+#if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
        java_lang_String *name;
-#elif defined(WITH_CLASSPATH_SUN) || defined(WITH_CLASSPATH_CLDC1_1)
+#elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK) || defined(WITH_JAVA_RUNTIME_LIBRARY_CLDC1_1)
        java_chararray_t *name;
 #endif
 
@@ -835,11 +931,11 @@ void thread_fprint_name(threadobject *t, FILE *stream)
 
        LLNI_field_get_ref(to, name, name);
 
-#if defined(WITH_CLASSPATH_GNU)
+#if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
 
        javastring_fprint((java_handle_t *) name, stream);
 
-#elif defined(WITH_CLASSPATH_SUN) || defined(WITH_CLASSPATH_CLDC1_1)
+#elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK) || defined(WITH_JAVA_RUNTIME_LIBRARY_CLDC1_1)
 
        /* FIXME: In OpenJDK and CLDC the name is a char[]. */
        /* FIXME This prints to stdout. */
@@ -863,6 +959,7 @@ void thread_fprint_name(threadobject *t, FILE *stream)
 void thread_print_info(threadobject *t)
 {
        java_lang_Thread *to;
+       int               state;
 
        /* If the thread is currently in initalization, don't print it. */
 
@@ -899,7 +996,9 @@ void thread_print_info(threadobject *t)
 
        /* Print thread state. */
 
-       switch (t->state) {
+       state = cacaothread_get_state(t);
+
+       switch (state) {
        case THREAD_STATE_NEW:
                printf(" new");
                break;
@@ -919,7 +1018,7 @@ void thread_print_info(threadobject *t)
                printf(" terminated");
                break;
        default:
-               vm_abort("thread_print_info: unknown thread state %d", t->state);
+               vm_abort("thread_print_info: unknown thread state %d", state);
        }
 }
 
@@ -948,7 +1047,7 @@ intptr_t threads_get_current_tid(void)
 }
 
 
-/* threads_thread_state_runnable ***********************************************
+/* thread_set_state_runnable ***************************************************
 
    Set the current state of the given thread to THREAD_STATE_RUNNABLE.
 
@@ -957,22 +1056,23 @@ intptr_t threads_get_current_tid(void)
 
 *******************************************************************************/
 
-void threads_thread_state_runnable(threadobject *t)
+void thread_set_state_runnable(threadobject *t)
 {
        /* Set the state inside a lock. */
 
        threadlist_lock();
 
-       if (t->state != THREAD_STATE_TERMINATED)
+       if (t->state != THREAD_STATE_TERMINATED) {
                t->state = THREAD_STATE_RUNNABLE;
 
-       DEBUGTHREADS("is RUNNABLE", t);
+               DEBUGTHREADS("is RUNNABLE", t);
+       }
 
        threadlist_unlock();
 }
 
 
-/* threads_thread_state_waiting ************************************************
+/* thread_set_state_waiting ****************************************************
 
    Set the current state of the given thread to THREAD_STATE_WAITING.
 
@@ -981,22 +1081,23 @@ void threads_thread_state_runnable(threadobject *t)
 
 *******************************************************************************/
 
-void threads_thread_state_waiting(threadobject *t)
+void thread_set_state_waiting(threadobject *t)
 {
        /* Set the state inside a lock. */
 
        threadlist_lock();
 
-       if (t->state != THREAD_STATE_TERMINATED)
+       if (t->state != THREAD_STATE_TERMINATED) {
                t->state = THREAD_STATE_WAITING;
 
-       DEBUGTHREADS("is WAITING", t);
+               DEBUGTHREADS("is WAITING", t);
+       }
 
        threadlist_unlock();
 }
 
 
-/* threads_thread_state_timed_waiting ******************************************
+/* thread_set_state_timed_waiting **********************************************
 
    Set the current state of the given thread to
    THREAD_STATE_TIMED_WAITING.
@@ -1006,31 +1107,32 @@ void threads_thread_state_waiting(threadobject *t)
 
 *******************************************************************************/
 
-void threads_thread_state_timed_waiting(threadobject *t)
+void thread_set_state_timed_waiting(threadobject *t)
 {
        /* Set the state inside a lock. */
 
        threadlist_lock();
 
-       if (t->state != THREAD_STATE_TERMINATED)
+       if (t->state != THREAD_STATE_TERMINATED) {
                t->state = THREAD_STATE_TIMED_WAITING;
 
-       DEBUGTHREADS("is TIMED_WAITING", t);
+               DEBUGTHREADS("is TIMED_WAITING", t);
+       }
 
        threadlist_unlock();
 }
 
 
-/* threads_thread_state_terminated *********************************************
+/* thread_set_state_terminated *************************************************
 
    Set the current state of the given thread to
    THREAD_STATE_TERMINATED.
 
 *******************************************************************************/
 
-void threads_thread_state_terminated(threadobject *t)
+void thread_set_state_terminated(threadobject *t)
 {
-       /* set the state in the lock */
+       /* Set the state inside a lock. */
 
        threadlist_lock();
 
@@ -1042,47 +1144,6 @@ void threads_thread_state_terminated(threadobject *t)
 }
 
 
-/* threads_thread_get_state ****************************************************
-
-   Returns the current state of the given thread.
-
-*******************************************************************************/
-
-utf *threads_thread_get_state(threadobject *t)
-{
-       utf *u;
-
-       switch (t->state) {
-       case THREAD_STATE_NEW:
-               u = utf_new_char("NEW");
-               break;
-       case THREAD_STATE_RUNNABLE:
-               u = utf_new_char("RUNNABLE");
-               break;
-       case THREAD_STATE_BLOCKED:
-               u = utf_new_char("BLOCKED");
-               break;
-       case THREAD_STATE_WAITING:
-               u = utf_new_char("WAITING");
-               break;
-       case THREAD_STATE_TIMED_WAITING:
-               u = utf_new_char("TIMED_WAITING");
-               break;
-       case THREAD_STATE_TERMINATED:
-               u = utf_new_char("TERMINATED");
-               break;
-       default:
-               vm_abort("threads_get_state: unknown thread state %d", t->state);
-
-               /* keep compiler happy */
-
-               u = NULL;
-       }
-
-       return u;
-}
-
-
 /* thread_get_thread **********************************************************
 
    Return the thread data structure of the given Java thread object.
@@ -1098,15 +1159,15 @@ utf *threads_thread_get_state(threadobject *t)
 threadobject *thread_get_thread(java_handle_t *h)
 {
        threadobject       *t;
-#if defined(WITH_CLASSPATH_GNU)
+#if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
        java_lang_VMThread *vmto;
        java_lang_Object   *to;
 #endif
-#if defined(WITH_CLASSPATH_SUN)
+#if defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
        bool                equal;
 #endif
 
-#if defined(WITH_CLASSPATH_GNU)
+#if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
 
        vmto = (java_lang_VMThread *) h;
 
@@ -1114,7 +1175,7 @@ threadobject *thread_get_thread(java_handle_t *h)
 
        t = (threadobject *) to;
 
-#elif defined(WITH_CLASSPATH_SUN)
+#elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
 
        /* XXX This is just a quick hack. */
 
@@ -1129,7 +1190,7 @@ threadobject *thread_get_thread(java_handle_t *h)
 
        threadlist_unlock();
 
-#elif defined(WITH_CLASSPATH_CLDC1_1)
+#elif defined(WITH_JAVA_RUNTIME_LIBRARY_CLDC1_1)
 
        log_println("threads_get_thread: IMPLEMENT ME!");
 
@@ -1149,7 +1210,11 @@ threadobject *thread_get_thread(java_handle_t *h)
 
 bool threads_thread_is_alive(threadobject *t)
 {
-       switch (t->state) {
+       int state;
+
+       state = cacaothread_get_state(t);
+
+       switch (state) {
        case THREAD_STATE_NEW:
        case THREAD_STATE_TERMINATED:
                return false;
@@ -1161,7 +1226,7 @@ bool threads_thread_is_alive(threadobject *t)
                return true;
 
        default:
-               vm_abort("threads_thread_is_alive: unknown thread state %d", t->state);
+               vm_abort("threads_thread_is_alive: unknown thread state %d", state);
        }
 
        /* keep compiler happy */
@@ -1212,7 +1277,7 @@ void threads_dump(void)
 
                /* Print trace of thread. */
 
-               threads_thread_print_stacktrace(t);
+               stacktrace_print_of_thread(t);
 
 #if defined(ENABLE_GC_CACAO)
                /* Resume the thread. */
@@ -1228,60 +1293,6 @@ void threads_dump(void)
 }
 
 
-/* threads_thread_print_stacktrace *********************************************
-
-   Print the current stacktrace of the given thread.
-
-*******************************************************************************/
-
-void threads_thread_print_stacktrace(threadobject *thread)
-{
-       stackframeinfo_t        *sfi;
-       java_handle_bytearray_t *ba;
-       stacktrace_t            *st;
-
-       /* Build a stacktrace for the passed thread. */
-
-       sfi = thread->_stackframeinfo;
-       ba  = stacktrace_get(sfi);
-       
-       if (ba != NULL) {
-               /* We need a critical section here as we use the byte-array
-                  data pointer directly. */
-
-               LLNI_CRITICAL_START;
-       
-               st = (stacktrace_t *) LLNI_array_data(ba);
-
-               /* Print stacktrace. */
-
-               stacktrace_print(st);
-
-               LLNI_CRITICAL_END;
-       }
-       else {
-               puts("\t<<No stacktrace available>>");
-               fflush(stdout);
-       }
-}
-
-
-/* threads_print_stacktrace ****************************************************
-
-   Print the current stacktrace of the current thread.
-
-*******************************************************************************/
-
-void threads_print_stacktrace(void)
-{
-       threadobject *thread;
-
-       thread = THREADOBJECT;
-
-       threads_thread_print_stacktrace(thread);
-}
-
-
 /*
  * 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