X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=src%2Fthreads%2Fposix%2Fthread-posix.cpp;h=a68cede39cf91c405bd86f2180fd3f137c519e65;hb=9d9877f7595070f5a7aedba5ae43a4b96a383a25;hp=949c1b59918df83aea78ccdf8531e0da4cc20eaa;hpb=9a310463406909b85dbed961b2265b7a383f8ad3;p=cacao.git diff --git a/src/threads/posix/thread-posix.cpp b/src/threads/posix/thread-posix.cpp index 949c1b599..a68cede39 100644 --- a/src/threads/posix/thread-posix.cpp +++ b/src/threads/posix/thread-posix.cpp @@ -1,6 +1,6 @@ /* src/threads/posix/thread-posix.cpp - POSIX thread functions - Copyright (C) 1996-2005, 2006, 2007, 2008 + Copyright (C) 1996-2005, 2006, 2007, 2008, 2010 CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO This file is part of CACAO. @@ -27,6 +27,8 @@ /* XXX cleanup these includes */ +#define __STDC_LIMIT_MACROS + #include #include #include @@ -43,7 +45,7 @@ #include "arch.h" #include "mm/gc.hpp" -#include "mm/memory.h" +#include "mm/memory.hpp" #if defined(ENABLE_GC_CACAO) # include "mm/cacao-gc/gc.h" @@ -58,15 +60,17 @@ #include "threads/threadlist.hpp" #include "threads/thread.hpp" -#include "toolbox/logging.h" +#include "toolbox/logging.hpp" #include "vm/jit/builtin.hpp" #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/signallocal.h" +#include "vm/os.hpp" +#include "vm/signallocal.hpp" #include "vm/string.hpp" #include "vm/vm.hpp" @@ -76,7 +80,15 @@ #include "vm/jit/asmpart.h" -#if !defined(__DARWIN__) +#if defined(__DARWIN__) + +typedef struct { + Mutex* mutex; + Condition* cond; + int value; +} sem_t; + +#else # include #endif @@ -86,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) @@ -94,10 +108,6 @@ # 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 @@ -545,21 +555,21 @@ void threads_impl_thread_free(threadobject *t) result = pthread_cond_destroy(&(t->flc_cond)); if (result != 0) - vm_abort_errnum(result, "threads_impl_thread_free: pthread_cond_destroy failed"); + os::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"); + os::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"); + os::abort_errnum(result, "threads_impl_thread_free: pthread_cond_destroy failed"); } #endif @@ -575,8 +585,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 @@ -593,9 +601,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 } @@ -669,12 +677,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"); } @@ -792,12 +800,8 @@ 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); @@ -821,17 +825,6 @@ static void *threads_startup_thread(void *arg) 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. @@ -851,17 +844,6 @@ static void *threads_startup_thread(void *arg) (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)(); @@ -869,22 +851,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; } @@ -925,33 +898,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 */ @@ -1136,134 +1109,146 @@ bool thread_detach_current_thread(void) } -/* 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(); + threadobject* thread = THREADOBJECT; - if (thread->suspended) { - thread->suspendmutex->unlock(); - return false; - } - - /* 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; + // Sanity check. + assert(reason != SUSPEND_REASON_NONE); - assert(thread->suspend_reason != 0); + // Guard this with the suspension mutex. + MutexLocker ml(*thread->suspendmutex); - /* TODO: remember dump memory size */ - - /* 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(); } - - /* 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); + else { + // Send the suspend signal to the other thread. + if (pthread_kill(thread->tid, SIGUSR1) != 0) + os::abort_errno("threads_suspend_thread: pthread_kill failed"); + + // 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 **************************************************** @@ -1381,7 +1366,10 @@ static void threads_wait_with_timeout(threadobject *t, struct timespec *wakeupTi while (!t->interrupted && !(parking ? t->park_permit : t->signaled) && threads_current_time_is_earlier_than(wakeupTime)) { - thread_set_state_timed_waiting(t); + if (parking) + thread_set_state_timed_parked(t); + else + thread_set_state_timed_waiting(t); t->waitcond->timedwait(t->waitmutex, wakeupTime); @@ -1391,7 +1379,10 @@ static void threads_wait_with_timeout(threadobject *t, struct timespec *wakeupTi else { /* no timeout */ while (!t->interrupted && !(parking ? t->park_permit : t->signaled)) { - thread_set_state_waiting(t); + if (parking) + thread_set_state_parked(t); + else + thread_set_state_waiting(t); t->waitcond->wait(t->waitmutex); @@ -1449,20 +1440,26 @@ void threads_wait_with_timeout_relative(threadobject *thread, s8 millis, static void threads_calc_absolute_time(struct timespec *tm, s8 millis, s4 nanos) { - if ((millis != 0x7fffffffffffffffLLU) && (millis || nanos)) { + // (at least with GNU classpath) we know that 0 <= nanos <= 999999 + do { + if (!millis && !nanos) + break; struct timeval tv; - long nsec; gettimeofday(&tv, NULL); - tv.tv_sec += millis / 1000; + s8 secs = tv.tv_sec + millis / 1000; + if (secs > INT32_MAX) // integer overflow + break; + tv.tv_sec = secs; millis %= 1000; - nsec = tv.tv_usec * 1000 + (s4) millis * 1000000 + nanos; + long nsec = tv.tv_usec * 1000 + (s4) millis * 1000000 + nanos; tm->tv_sec = tv.tv_sec + nsec / 1000000000; + if (tm->tv_sec < tv.tv_sec) // integer overflow + break; tm->tv_nsec = nsec % 1000000000; - } - else { - tm->tv_sec = 0; - tm->tv_nsec = 0; - } + return; + } while (0); + tm->tv_sec = 0; + tm->tv_nsec = 0; }