* src/threads/posix/thread-posix.cpp: Take care not to signal threads after
[cacao.git] / src / threads / posix / thread-posix.cpp
index bcc25c9f137b8f6d765ab08195506ab18080b46f..820d7260ee470ec645ce03c82945bd3a3a9bae93 100644 (file)
@@ -1,6 +1,6 @@
 /* src/threads/posix/thread-posix.cpp - POSIX thread functions
 
-   Copyright (C) 1996-2005, 2006, 2007, 2008
+   Copyright (C) 1996-2011
    CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
 
    This file is part of CACAO.
 #include "vm/exceptions.hpp"
 #include "vm/global.h"
 #include "vm/globals.hpp"
+#include "vm/hook.hpp"
 #include "vm/javaobjects.hpp"
 #include "vm/options.h"
+#include "vm/os.hpp"
 #include "vm/signallocal.hpp"
 #include "vm/string.hpp"
 #include "vm/vm.hpp"
 
 #include "vm/jit/asmpart.h"
 
-#if !defined(__DARWIN__)
+#if defined(__DARWIN__)
+
+typedef struct {
+       Mutex* mutex;
+       Condition* cond;
+       int value;
+} sem_t;
+
+#else
 # include <semaphore.h>
 #endif
 
@@ -88,6 +98,8 @@
 # define GC_IRIX_THREADS
 #elif defined(__DARWIN__)
 # define GC_DARWIN_THREADS
+#elif defined(__SOLARIS__)
+# define GC_SOLARIS_THREADS
 #endif
 
 #if defined(ENABLE_GC_BOEHM)
 # include "mm/boehm-gc/include/gc.h"
 #endif
 
-#if defined(ENABLE_JVMTI)
-#include "native/jvmti/cacaodbg.h"
-#endif
-
 
 #if defined(__DARWIN__)
 /* Darwin has no working semaphore implementation.  This one is taken
@@ -525,47 +533,6 @@ void threads_impl_thread_reuse(threadobject *t)
 }
 
 
-/* threads_impl_thread_free ****************************************************
-
-   Cleanup thread stuff.
-
-   IN:
-      t....the threadobject
-
-*******************************************************************************/
-
-#if 0
-/* never used */
-void threads_impl_thread_free(threadobject *t)
-{
-       int result;
-
-       /* Destroy the mutex and the condition. */
-
-       delete t->flc_lock;
-
-       result = pthread_cond_destroy(&(t->flc_cond));
-
-       if (result != 0)
-               vm_abort_errnum(result, "threads_impl_thread_free: pthread_cond_destroy failed");
-
-       delete t->waitmutex;
-
-       result = pthread_cond_destroy(&(t->waitcond));
-
-       if (result != 0)
-               vm_abort_errnum(result, "threads_impl_thread_free: pthread_cond_destroy failed");
-
-       delete t->suspendmutex;
-
-       result = pthread_cond_destroy(&(t->suspendcond));
-
-       if (result != 0)
-               vm_abort_errnum(result, "threads_impl_thread_free: pthread_cond_destroy failed");
-}
-#endif
-
-
 /* threads_impl_preinit ********************************************************
 
    Do some early initialization of stuff required.
@@ -577,8 +544,6 @@ void threads_impl_thread_free(threadobject *t)
 
 void threads_impl_preinit(void)
 {
-       int result;
-
        stopworldlock = new Mutex();
 
        /* initialize exit mutex and condition (on exit we join all
@@ -595,9 +560,9 @@ void threads_impl_preinit(void)
 #endif
 
 #if !defined(HAVE___THREAD)
-       result = pthread_key_create(&thread_current_key, NULL);
+       int result = pthread_key_create(&thread_current_key, NULL);
        if (result != 0)
-               vm_abort_errnum(result, "threads_impl_preinit: pthread_key_create failed");
+               os::abort_errnum(result, "threads_impl_preinit: pthread_key_create failed");
 #endif
 }
 
@@ -671,12 +636,12 @@ void threads_impl_init(void)
        result = pthread_attr_init(&attr);
 
        if (result != 0)
-               vm_abort_errnum(result, "threads_impl_init: pthread_attr_init failed");
+               os::abort_errnum(result, "threads_impl_init: pthread_attr_init failed");
 
        result = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
 
        if (result != 0)
-               vm_abort_errnum(result, "threads_impl_init: pthread_attr_setdetachstate failed");
+               os::abort_errnum(result, "threads_impl_init: pthread_attr_setdetachstate failed");
 }
 
 
@@ -794,76 +759,28 @@ static void *threads_startup_thread(void *arg)
                thread->_global_sp = (Cell *) (intrp_thread_stack + opt_stacksize);
 #endif
 
-#if defined(ENABLE_JVMTI)
-       /* fire thread start event */
-
-       if (jvmti) 
-               jvmti_ThreadStartEnd(JVMTI_EVENT_THREAD_START);
-#endif
+       // Hook point just before the threads initial method is executed.
+       Hook::thread_start(t);
 
        DEBUGTHREADS("starting", t);
 
        /* find and run the Thread.run()V method if no other function was passed */
 
        if (function == NULL) {
-#if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
-               /* 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_JAVA_RUNTIME_LIBRARY_OPENJDK) || defined(WITH_JAVA_RUNTIME_LIBRARY_CLDC1_1)
-               LLNI_class_get(object, c);
-#else
-# error unknown classpath configuration
-#endif
+               c = ThreadRuntime::get_thread_class_from_object(object);
 
                m = class_resolveclassmethod(c, utf_run, utf_void__void, c, true);
 
                if (m == NULL)
                        vm_abort("threads_startup_thread: run() method not found in class");
 
-               /* set ThreadMXBean variables */
-
-/*             _Jv_jvm->java_lang_management_ThreadMXBean_ThreadCount++; */
-/*             _Jv_jvm->java_lang_management_ThreadMXBean_TotalStartedThreadCount++; */
-
-/*             if (_Jv_jvm->java_lang_management_ThreadMXBean_ThreadCount > */
-/*                     _Jv_jvm->java_lang_management_ThreadMXBean_PeakThreadCount) */
-/*                     _Jv_jvm->java_lang_management_ThreadMXBean_PeakThreadCount = */
-/*                             _Jv_jvm->java_lang_management_ThreadMXBean_ThreadCount; */
-#warning Move to C++
-
-#if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
-
-               // We need to start the run method of java.lang.VMThread.
-               java_lang_VMThread jlvmt(jlt.get_vmThread());
-               java_handle_t* h = jlvmt.get_handle();
-
-#elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK) || defined(WITH_JAVA_RUNTIME_LIBRARY_CLDC1_1)
-
-               java_handle_t* h = jlt.get_handle();
-
-#else
-# error unknown classpath configuration
-#endif
+               java_handle_t *h = ThreadRuntime::get_vmthread_handle(jlt);
 
                /* Run the thread. */
 
                (void) vm_call_method(m, h);
        }
        else {
-               /* set ThreadMXBean variables */
-
-/*             _Jv_jvm->java_lang_management_ThreadMXBean_ThreadCount++; */
-/*             _Jv_jvm->java_lang_management_ThreadMXBean_TotalStartedThreadCount++; */
-
-/*             if (_Jv_jvm->java_lang_management_ThreadMXBean_ThreadCount > */
-/*                     _Jv_jvm->java_lang_management_ThreadMXBean_PeakThreadCount) */
-/*                     _Jv_jvm->java_lang_management_ThreadMXBean_PeakThreadCount = */
-/*                             _Jv_jvm->java_lang_management_ThreadMXBean_ThreadCount; */
-#warning Move to C++
-
                /* call passed function, e.g. finalizer_thread */
 
                (function)();
@@ -871,22 +788,13 @@ static void *threads_startup_thread(void *arg)
 
        DEBUGTHREADS("stopping", t);
 
-#if defined(ENABLE_JVMTI)
-       /* fire thread end event */
-
-       if (jvmti)
-               jvmti_ThreadStartEnd(JVMTI_EVENT_THREAD_END);
-#endif
+       // Hook point just after the threads initial method returned.
+       Hook::thread_end(t);
 
        /* We ignore the return value. */
 
        (void) thread_detach_current_thread();
 
-       /* set ThreadMXBean variables */
-
-/*     _Jv_jvm->java_lang_management_ThreadMXBean_ThreadCount--; */
-#warning Move to C++
-
        return NULL;
 }
 
@@ -927,33 +835,33 @@ void threads_impl_thread_start(threadobject *thread, functionptr f)
        result = pthread_attr_init(&attr);
 
        if (result != 0)
-               vm_abort_errnum(result, "threads_impl_thread_start: pthread_attr_init failed");
+               os::abort_errnum(result, "threads_impl_thread_start: pthread_attr_init failed");
 
     result = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
 
     if (result != 0)
-               vm_abort_errnum(result, "threads_impl_thread_start: pthread_attr_setdetachstate failed");
+               os::abort_errnum(result, "threads_impl_thread_start: pthread_attr_setdetachstate failed");
 
        /* initialize thread stacksize */
 
        result = pthread_attr_setstacksize(&attr, opt_stacksize);
 
        if (result != 0)
-               vm_abort_errnum(result, "threads_impl_thread_start: pthread_attr_setstacksize failed");
+               os::abort_errnum(result, "threads_impl_thread_start: pthread_attr_setstacksize failed");
 
        /* create the thread */
 
        result = pthread_create(&(thread->tid), &attr, threads_startup_thread, &startup);
 
        if (result != 0)
-               vm_abort_errnum(result, "threads_impl_thread_start: pthread_create failed");
+               os::abort_errnum(result, "threads_impl_thread_start: pthread_create failed");
 
        /* destroy the thread attributes */
 
        result = pthread_attr_destroy(&attr);
 
        if (result != 0)
-               vm_abort_errnum(result, "threads_impl_thread_start: pthread_attr_destroy failed");
+               os::abort_errnum(result, "threads_impl_thread_start: pthread_attr_destroy failed");
 
        /* signal that pthread_create has returned, so thread->tid is valid */
 
@@ -1029,15 +937,7 @@ bool thread_detach_current_thread(void)
                   to build the java_lang_Thread_UncaughtExceptionHandler
                   header file with cacaoh. */
 
-# if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
-
-               java_handle_t* handler = jlt.get_exceptionHandler();
-
-# elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
-
-               java_handle_t* handler = jlt.get_uncaughtExceptionHandler();
-
-# endif
+               java_handle_t *handler = ThreadRuntime::get_thread_exception_handler(jlt);
 
                classinfo*     c;
                java_handle_t* h;
@@ -1074,21 +974,7 @@ bool thread_detach_current_thread(void)
                classinfo* c;
                LLNI_class_get(group, c);
 
-# if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
-               methodinfo* m = class_resolveclassmethod(c,
-                                                                                                utf_removeThread,
-                                                                                                utf_java_lang_Thread__V,
-                                                                                                class_java_lang_ThreadGroup,
-                                                                                                true);
-# elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
-               methodinfo* m = class_resolveclassmethod(c,
-                                                                                                utf_remove,
-                                                                                                utf_java_lang_Thread__V,
-                                                                                                class_java_lang_ThreadGroup,
-                                                                                                true);
-# else
-#  error unknown classpath configuration
-# endif
+               methodinfo *m = ThreadRuntime::get_threadgroup_remove_method(c);
 
                if (m == NULL)
                        return false;
@@ -1119,6 +1005,10 @@ bool thread_detach_current_thread(void)
        /* XXX Care about exceptions? */
        (void) lock_monitor_exit(jlt.get_handle());
 
+       t->waitmutex->lock();
+       t->tid = 0;
+       t->waitmutex->unlock();
+
        /* Enter the join-mutex before calling thread_free, so
           threads_join_all_threads gets the correct number of non-daemon
           threads. */
@@ -1134,138 +1024,155 @@ bool thread_detach_current_thread(void)
        cond_join->signal();
        threads_mutex_join_unlock();
 
+       t->suspendmutex->lock();
+       t->suspendmutex->unlock();
+
        return true;
 }
 
 
-/* threads_suspend_thread ******************************************************
-
-   Suspend the passed thread. Execution stops until the thread
-   is explicitly resumend again.
-
-   IN:
-     reason.....Reason for suspending this thread.
-
-*******************************************************************************/
-
-bool threads_suspend_thread(threadobject *thread, s4 reason)
+/**
+ * Internal helper function which suspends the current thread. This is
+ * the core method of the suspension mechanism actually blocking the
+ * execution until the suspension reason is cleared again. Note that
+ * the current thread needs to hold the suspension mutex while calling
+ * this function.
+ */
+static void threads_suspend_self()
 {
-       /* acquire the suspendmutex */
-       thread->suspendmutex->lock();
-
-       if (thread->suspended) {
-               thread->suspendmutex->unlock();
-               return false;
-       }
+       threadobject* thread = THREADOBJECT;
 
-       /* set the reason for the suspension */
-       thread->suspend_reason = reason;
+       DEBUGTHREADS("suspending", thread);
 
-       /* send the suspend signal to the thread */
-       assert(thread != THREADOBJECT);
-       if (pthread_kill(thread->tid, SIGUSR1) != 0)
-               vm_abort("threads_suspend_thread: pthread_kill failed: %s",
-                                strerror(errno));
+       // Mark thread as suspended.
+       assert(!thread->suspended);
+       assert(thread->suspend_reason != SUSPEND_REASON_NONE);
+       thread->suspended = true;
 
-       /* REMEMBER: do not release the suspendmutex, this is done
-          by the thread itself in threads_suspend_ack().  */
+       // Acknowledge the suspension.
+       thread->suspendcond->broadcast();
 
-       return true;
-}
+#if defined(ENABLE_GC_CACAO)
+       // If we are stopping the world, we should send a global ack.
+       if (thread->suspend_reason == SUSPEND_REASON_STOPWORLD)
+               threads_sem_post(&suspend_ack);
+#endif
 
+       // Release the suspension mutex and wait till we are resumed.
+       thread->suspendcond->wait(thread->suspendmutex);
 
-/* threads_suspend_ack *********************************************************
+#if defined(ENABLE_GC_CACAO)
+       // XXX This is propably not ok!
+       // If we are starting the world, we should send a global ack.
+       if (thread->suspend_reason == SUSPEND_REASON_STOPWORLD)
+               threads_sem_post(&suspend_ack);
+#endif
 
-   Acknowledges the suspension of the current thread.
+       // Mark thread as not suspended.
+       assert(thread->suspended);
+       assert(thread->suspend_reason == SUSPEND_REASON_NONE);
+       thread->suspended = false;
 
-   IN:
-     pc.....The PC where the thread suspended its execution.
-     sp.....The SP before the thread suspended its execution.
+       DEBUGTHREADS("resuming", thread);
+}
 
-*******************************************************************************/
 
-#if defined(ENABLE_GC_CACAO)
-void threads_suspend_ack(u1* pc, u1* sp)
+/**
+ * Suspend the passed thread. Execution of that thread stops until the thread
+ * is explicitly resumend again.
+ *
+ * @param thread The thread to be suspended.
+ * @param reason Reason for suspending the given thread.
+ * @return True of operation was successful, false otherwise.
+ */
+bool threads_suspend_thread(threadobject *thread, int32_t reason)
 {
-       threadobject *thread;
-
-       thread = THREADOBJECT;
-
-       assert(thread->suspend_reason != 0);
+       // Sanity check.
+       assert(reason != SUSPEND_REASON_NONE);
 
-       /* TODO: remember dump memory size */
+       // Guard this with the suspension mutex.
+       MutexLocker ml(*thread->suspendmutex);
 
-       /* inform the GC about the suspension */
-       if (thread->suspend_reason == SUSPEND_REASON_STOPWORLD && gc_pending) {
+       // Check if thread is already suspended.
+       if (thread->suspended)
+               return false;
 
-               /* check if the GC wants to leave the thread running */
-               if (!gc_suspend(thread, pc, sp)) {
+       // Check if thread is in the process of suspending.
+       if (thread->suspend_reason != SUSPEND_REASON_NONE)
+               return false;
 
-                       /* REMEMBER: we do not unlock the suspendmutex because the thread
-                          will suspend itself again at a later time */
-                       return;
+       // Set the reason for suspending the thread.
+       thread->suspend_reason = reason;
 
-               }
+       if (thread == THREADOBJECT) {
+               // We already hold the suspension mutex and can suspend ourselves
+               // immediately without using signals at all.
+               threads_suspend_self();
        }
+       else {
+               // Send the suspend signal to the other thread.
+               if (!thread->tid)
+                       return false;
+               if (pthread_kill(thread->tid, SIGUSR1) != 0)
+                       os::abort_errno("threads_suspend_thread: pthread_kill failed");
 
-       /* mark this thread as suspended and remember the PC */
-       thread->pc        = pc;
-       thread->suspended = true;
-
-       /* if we are stopping the world, we should send a global ack */
-       if (thread->suspend_reason == SUSPEND_REASON_STOPWORLD) {
-               threads_sem_post(&suspend_ack);
+               // Wait for the thread to acknowledge the suspension.
+               // XXX A possible optimization would be to not wait here, but you
+               //     better think this through twice before trying it!
+               thread->suspendcond->wait(thread->suspendmutex);
        }
 
-       DEBUGTHREADS("suspending", thread);
+       return true;
+}
 
-       /* release the suspension mutex and wait till we are resumed */
-       thread->suspendcond->wait(thread->suspendmutex);
 
-       DEBUGTHREADS("resuming", thread);
+/**
+ * Resumes execution of the passed thread.
+ *
+ * @param thread The thread to be resumed.
+ * @param reason Reason for suspending the given thread.
+ * @return True of operation was successful, false otherwise.
+ */
+bool threads_resume_thread(threadobject *thread, int32_t reason)
+{
+       // Sanity check.
+       assert(thread != THREADOBJECT);
+       assert(reason != SUSPEND_REASON_NONE);
 
-       /* if we are stopping the world, we should send a global ack */
-       if (thread->suspend_reason == SUSPEND_REASON_STOPWORLD) {
-               threads_sem_post(&suspend_ack);
-       }
+       // Guard this with the suspension mutex.
+       MutexLocker ml(*thread->suspendmutex);
 
-       /* TODO: free dump memory */
+       // Check if thread really is suspended.
+       if (!thread->suspended)
+               return false;
 
-       /* release the suspendmutex */
-       thread->suspendmutex->unlock();
-}
-#endif
+       // Threads can only be resumed for the same reason they were suspended.
+       if (thread->suspend_reason != reason)
+               return false;
 
+       // Clear the reason for suspending the thread.
+       thread->suspend_reason = SUSPEND_REASON_NONE;
 
-/* threads_resume_thread *******************************************************
+       // Tell everyone that the thread should resume.
+       thread->suspendcond->broadcast();
 
-   Resumes the execution of the passed thread.
+       return true;
+}
 
-*******************************************************************************/
 
-#if defined(ENABLE_GC_CACAO)
-bool threads_resume_thread(threadobject *thread)
+/**
+ * Acknowledges the suspension of the current thread.
+ */
+void threads_suspend_ack()
 {
-       /* acquire the suspendmutex */
-       thread->suspendmutex->lock();
-
-       if (!thread->suspended) {
-               thread->suspendmutex->unlock();
-               return false;
-       }
+       threadobject* thread = THREADOBJECT;
 
-       thread->suspended = false;
+       // Guard this with the suspension mutex.
+       MutexLocker ml(*thread->suspendmutex);
 
-       /* tell everyone that the thread should resume */
-       assert(thread != THREADOBJECT);
-       thread->suspendcond->broadcast();
-
-       /* release the suspendmutex */
-       thread->suspendmutex->unlock();
-
-       return true;
+       // Suspend ourselves while holding the suspension mutex.
+       threads_suspend_self();
 }
-#endif
 
 
 /* threads_join_all_threads ****************************************************
@@ -1503,7 +1410,8 @@ void threads_thread_interrupt(threadobject *t)
 
        /* Interrupt blocking system call using a signal. */
 
-       pthread_kill(t->tid, Signal_INTERRUPT_SYSTEM_CALL);
+       if (t->tid)
+               pthread_kill(t->tid, Signal_INTERRUPT_SYSTEM_CALL);
 
        t->waitcond->signal();