/* 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.
/* XXX cleanup these includes */
+#define __STDC_LIMIT_MACROS
+
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#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"
#endif
-#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"
-
-#if defined(ENABLE_JAVASE)
-# include "native/include/java_lang_ThreadGroup.h"
-#endif
-
-#if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
-# include "native/include/java_lang_VMThread.h"
-#endif
+#include "native/native.hpp"
#include "threads/condition.hpp"
-#include "threads/lock-common.h"
+#include "threads/lock.hpp"
#include "threads/mutex.hpp"
-#include "threads/threadlist.h"
+#include "threads/threadlist.hpp"
#include "threads/thread.hpp"
-#include "toolbox/logging.h"
+#include "toolbox/logging.hpp"
-#include "vm/builtin.h"
+#include "vm/jit/builtin.hpp"
#include "vm/exceptions.hpp"
#include "vm/global.h"
-#include "vm/signallocal.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"
+#if defined(ENABLE_STATISTICS)
+# include "vm/statistics.h"
+#endif
+
#include "vm/jit/asmpart.h"
-#include "vmcore/globals.hpp"
-#include "vmcore/options.h"
+#if defined(__DARWIN__)
-#if defined(ENABLE_STATISTICS)
-# include "vmcore/statistics.h"
-#endif
+typedef struct {
+ Mutex* mutex;
+ Condition* cond;
+ int value;
+} sem_t;
-#if !defined(__DARWIN__)
+#else
# include <semaphore.h>
#endif
# 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
-
-
-// FIXME For now we export everything as C functions.
-extern "C" {
#if defined(__DARWIN__)
/* Darwin has no working semaphore implementation. This one is taken
from Boehm-GC. */
/*
- This is a very simple semaphore implementation for darwin. It
+ This is a very simple semaphore implementation for Darwin. It
is implemented in terms of pthreads calls so it isn't async signal
safe. This isn't a problem because signals aren't used to
- suspend threads on darwin.
+ suspend threads on Darwin.
*/
static int sem_init(sem_t *sem, int pshared, int value)
if (pshared)
assert(0);
- sem->value = value;
-
sem->mutex = new Mutex();
-
- if (pthread_cond_init(&sem->cond, NULL) < 0)
- return -1;
+ sem->cond = new Condition();
+ sem->value = value;
return 0;
}
static int sem_post(sem_t *sem)
{
sem->mutex->lock();
-
sem->value++;
-
- if (pthread_cond_signal(&sem->cond) < 0) {
- sem->mutex->unlock();
- return -1;
- }
-
+ sem->cond->signal();
sem->mutex->unlock();
return 0;
sem->mutex->lock();
while (sem->value == 0) {
-#error We cannot call pthread_cond_wait on a Mutex-class pointer.
- pthread_cond_wait(&sem->cond, &sem->mutex);
+ sem->cond->wait(sem->mutex);
}
sem->value--;
-
sem->mutex->unlock();
return 0;
static int sem_destroy(sem_t *sem)
{
- if (pthread_cond_destroy(&sem->cond) < 0)
- return -1;
-
+ delete sem->cond;
delete sem->mutex;
return 0;
#endif
-/* threads_impl_thread_init ****************************************************
-
- Initialize OS-level locking constructs in threadobject.
-
- IN:
- t....the threadobject
-
-*******************************************************************************/
-
-void threads_impl_thread_init(threadobject *t)
-{
- /* initialize the mutex and the condition */
-
- t->flc_lock = new Mutex();
- t->flc_cond = new Condition();
-
- t->waitmutex = new Mutex();
- t->waitcond = new Condition();
-
- t->suspendmutex = new Mutex();
- t->suspendcond = new Condition();
-
-#if defined(ENABLE_TLH)
- tlh_init(&(t->tlh));
-#endif
-}
-
/* threads_impl_thread_clear ***************************************************
Clears all fields in threadobject the way an MZERO would have
t->es = NULL;
#endif
- MZERO(&t->dumpinfo, dumpinfo_t, 1);
+ // Simply reuse the existing dump memory.
}
/* threads_impl_thread_reuse ***************************************************
}
-/* 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.
void threads_impl_preinit(void)
{
- int result;
-
stopworldlock = new Mutex();
/* initialize exit mutex and condition (on exit we join all
#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
}
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");
}
static void *threads_startup_thread(void *arg)
{
- startupinfo *startup;
- threadobject *t;
- java_lang_Thread *object;
-#if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
- java_lang_VMThread *vmt;
-#endif
- sem_t *psem;
- classinfo *c;
- methodinfo *m;
- java_handle_t *o;
- functionptr function;
+ startupinfo *startup;
+ threadobject *t;
+ sem_t *psem;
+ classinfo *c;
+ methodinfo *m;
+ functionptr function;
#if defined(ENABLE_GC_BOEHM)
# if !defined(__DARWIN__)
# endif
#endif
- /* get the java.lang.Thread object for this thread */
-
- object = (java_lang_Thread *) thread_get_object(t);
+ // Get the java.lang.Thread object for this thread.
+ java_handle_t* object = thread_get_object(t);
+ java_lang_Thread jlt(object);
/* set our priority */
- threads_set_thread_priority(t->tid, LLNI_field_direct(object, priority));
+ threads_set_thread_priority(t->tid, jlt.get_priority());
/* Thread is completely initialized. */
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 */
-
- LLNI_field_get_ref(object, vmThread, vmt);
- o = (java_handle_t *) vmt;
-
-#elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK) || defined(WITH_JAVA_RUNTIME_LIBRARY_CLDC1_1)
- o = (java_handle_t *) object;
-#else
-# error unknown classpath configuration
-#endif
+ java_handle_t *h = ThreadRuntime::get_vmthread_handle(jlt);
/* Run the thread. */
- (void) vm_call_method(m, o);
+ (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)();
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;
}
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 */
*/
bool thread_detach_current_thread(void)
{
- threadobject *t;
- bool result;
- java_lang_Thread *object;
- java_handle_t *o;
-#if defined(ENABLE_JAVASE)
- java_lang_ThreadGroup *group;
- java_handle_t *e;
- void *handler;
- classinfo *c;
- methodinfo *m;
-#endif
-
- t = thread_get_current();
+ threadobject* t = thread_get_current();
/* Sanity check. */
/* If the given thread has already been detached, this operation
is a no-op. */
- result = thread_is_attached(t);
-
- if (result == false)
+ if (thread_is_attached(t) == false)
return true;
DEBUGTHREADS("detaching", t);
- object = (java_lang_Thread *) thread_get_object(t);
+ java_handle_t* object = thread_get_object(t);
+ java_lang_Thread jlt(object);
#if defined(ENABLE_JAVASE)
- LLNI_field_get_ref(object, group, group);
+ java_handle_t* group = jlt.get_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();
+ java_handle_t* e = exceptions_get_and_clear_exception();
if (e != NULL) {
/* We use the type void* for handler here, as it's not trivial
to build the java_lang_Thread_UncaughtExceptionHandler
header file with cacaoh. */
-# if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
- LLNI_field_get_ref(object, exceptionHandler, handler);
-# elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
- LLNI_field_get_ref(object, uncaughtExceptionHandler, handler);
-# endif
+ java_handle_t *handler = ThreadRuntime::get_thread_exception_handler(jlt);
+
+ classinfo* c;
+ java_handle_t* h;
if (handler != NULL) {
LLNI_class_get(handler, c);
- o = (java_handle_t *) handler;
+ h = (java_handle_t *) handler;
}
else {
LLNI_class_get(group, c);
- o = (java_handle_t *) group;
+ h = (java_handle_t *) group;
}
- m = class_resolveclassmethod(c,
- utf_uncaughtException,
- utf_java_lang_Thread_java_lang_Throwable__V,
- NULL,
- true);
+ methodinfo* m = class_resolveclassmethod(c,
+ utf_uncaughtException,
+ utf_java_lang_Thread_java_lang_Throwable__V,
+ NULL,
+ true);
if (m == NULL)
return false;
- (void) vm_call_method(m, o, object, e);
+ (void) vm_call_method(m, h, object, e);
if (exceptions_get_exception())
return false;
/* Remove thread from the thread group. */
if (group != NULL) {
+ classinfo* c;
LLNI_class_get(group, c);
-# if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
- m = class_resolveclassmethod(c,
- utf_removeThread,
- utf_java_lang_Thread__V,
- class_java_lang_ThreadGroup,
- true);
-# elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
- 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;
- o = (java_handle_t *) group;
-
- (void) vm_call_method(m, o, object);
+ (void) vm_call_method(m, group, object);
if (exceptions_get_exception())
return false;
- /* Reset the threadgroup in the Java thread object (Mauve
- test: gnu/testlet/java/lang/Thread/getThreadGroup). */
-
- LLNI_field_set_ref(object, group, NULL);
+ // Clear the ThreadGroup in the Java thread object (Mauve
+ // test: gnu/testlet/java/lang/Thread/getThreadGroup).
+ jlt.set_group(NULL);
}
#endif
/* Notify all threads waiting on this thread. These are joining
this thread. */
- o = (java_handle_t *) object;
-
/* XXX Care about exceptions? */
- (void) lock_monitor_enter(o);
+ (void) lock_monitor_enter(jlt.get_handle());
- lock_notify_all_object(o);
+ lock_notify_all_object(jlt.get_handle());
/* XXX Care about exceptions? */
- (void) lock_monitor_exit(o);
+ (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
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();
+ threadobject* thread = THREADOBJECT;
- if (!thread->suspended) {
- thread->suspendmutex->unlock();
- return false;
- }
-
- 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 ****************************************************
compare against 1 because the current (main thread) is also a
non-daemon thread. */
- while (threadlist_get_non_daemons() > 1)
+ while (ThreadList::get_number_of_non_daemon_threads() > 1)
cond_join->wait(mutex_join);
/* leave join mutex */
*******************************************************************************/
-static void threads_wait_with_timeout(threadobject *t, struct timespec *wakeupTime)
+static void threads_wait_with_timeout(threadobject *t, struct timespec *wakeupTime, bool parking)
{
// Acquire the waitmutex.
t->waitmutex->lock();
if (wakeupTime->tv_sec || wakeupTime->tv_nsec) {
/* with timeout */
- while (!t->interrupted && !t->signaled
+ 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);
}
else {
/* no timeout */
- while (!t->interrupted && !t->signaled) {
- thread_set_state_waiting(t);
+ while (!t->interrupted && !(parking ? t->park_permit : t->signaled)) {
+ if (parking)
+ thread_set_state_parked(t);
+ else
+ thread_set_state_waiting(t);
t->waitcond->wait(t->waitmutex);
}
}
+ if (parking)
+ t->park_permit = false;
+
// Release the waitmutex.
t->waitmutex->unlock();
}
/* wait */
- threads_wait_with_timeout(thread, &wakeupTime);
+ threads_wait_with_timeout(thread, &wakeupTime, false);
}
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;
}
/* Interrupt blocking system call using a signal. */
- pthread_kill(t->tid, Signal_THREAD_INTERRUPT);
+ if (t->tid)
+ pthread_kill(t->tid, Signal_INTERRUPT_SYSTEM_CALL);
t->waitcond->signal();
}
-/* threads_sleep ***************************************************************
-
- Sleep the current thread for the specified amount of time.
-
-*******************************************************************************/
-
+/**
+ * Sleep the current thread for the specified amount of time.
+ *
+ * @param millis Milliseconds to sleep.
+ * @param nanos Nanoseconds to sleep.
+ */
void threads_sleep(int64_t millis, int32_t nanos)
{
threadobject *t;
return;
}
- threads_calc_absolute_time(&wakeupTime, millis, nanos);
+ // (Note taken from classpath/vm/reference/java/lang/VMThread.java (sleep))
+ // Note: JDK treats a zero length sleep is like Thread.yield(),
+ // without checking the interrupted status of the thread. It's
+ // unclear if this is a bug in the implementation or the spec.
+ // See http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6213203 */
+ if (millis == 0 && nanos == 0) {
+ threads_yield();
+ }
+ else {
+ threads_calc_absolute_time(&wakeupTime, millis, nanos);
- threads_wait_with_timeout(t, &wakeupTime);
+ threads_wait_with_timeout(t, &wakeupTime, false);
- interrupted = thread_is_interrupted(t);
+ interrupted = thread_is_interrupted(t);
- if (interrupted) {
- thread_set_interrupted(t, false);
+ if (interrupted) {
+ thread_set_interrupted(t, false);
- /* An other exception could have been thrown
- (e.g. ThreadDeathException). */
+ // An other exception could have been thrown
+ // (e.g. ThreadDeathException).
+ if (!exceptions_get_exception())
+ exceptions_throw_interruptedexception();
+ }
+ }
+}
- if (!exceptions_get_exception())
- exceptions_throw_interruptedexception();
+/**
+ * Park the current thread for the specified amount of time or until a
+ * specified deadline.
+ *
+ * @param absolute Is the time in nanos a deadline or a duration?
+ * @param nanos Nanoseconds to park (absolute=false)
+ * or deadline in milliseconds (absolute=true)
+ */
+void threads_park(bool absolute, int64_t nanos)
+{
+ threadobject *t;
+ struct timespec wakeupTime;
+
+ t = thread_get_current();
+
+ if (absolute) {
+ wakeupTime.tv_nsec = 0;
+ wakeupTime.tv_sec = nanos / 1000; /* milliseconds */
}
+ else
+ threads_calc_absolute_time(&wakeupTime, nanos / 1000000, nanos % 1000000);
+
+ threads_wait_with_timeout(t, &wakeupTime, true);
+}
+
+/**
+ * Unpark the specified thread.
+ *
+ * @param t The thread to unpark.
+ */
+void threads_unpark(threadobject *t)
+{
+ t->waitmutex->lock();
+
+ t->waitcond->signal();
+
+ t->park_permit = true;
+
+ t->waitmutex->unlock();
}
#endif
-} // extern "C"
-
/*
* These are local overrides for various environment variables in Emacs.