#include "arch.h"
-#if !defined(USE_FAKE_ATOMIC_INSTRUCTIONS)
-# include "machine-instr.h"
-#else
-# include "threads/posix/generic-primitives.h"
-#endif
-
#include "mm/gc-common.h"
#include "mm/memory.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/condition.hpp"
#include "threads/lock-common.h"
-#include "threads/mutex.h"
+#include "threads/mutex.hpp"
#include "threads/threadlist.h"
#include "threads/thread.h"
#endif
#if !defined(__DARWIN__)
-# if defined(__LINUX__)
-# define GC_LINUX_THREADS
-# elif defined(__IRIX__)
-# define GC_IRIX_THREADS
-# endif
# include <semaphore.h>
-# if defined(ENABLE_GC_BOEHM)
-# include "mm/boehm-gc/include/gc.h"
-# endif
+#endif
+
+#if defined(__LINUX__)
+# define GC_LINUX_THREADS
+#elif defined(__IRIX__)
+# define GC_IRIX_THREADS
+#elif defined(__DARWIN__)
+# define GC_DARWIN_THREADS
+#endif
+
+#if defined(ENABLE_GC_BOEHM)
+/* We need to include Boehm's gc.h here because it overrides
+ pthread_create and friends. */
+# include "mm/boehm-gc/include/gc.h"
#endif
#if defined(ENABLE_JVMTI)
sem->value = value;
- mutex_init(&sem->mutex);
+ sem->mutex = Mutex_new();
if (pthread_cond_init(&sem->cond, NULL) < 0)
return -1;
static int sem_post(sem_t *sem)
{
- mutex_lock(&sem->mutex);
+ Mutex_lock(sem->mutex);
sem->value++;
if (pthread_cond_signal(&sem->cond) < 0) {
- mutex_unlock(&sem->mutex);
+ Mutex_unlock(sem->mutex);
return -1;
}
- mutex_unlock(&sem->mutex);
+ Mutex_unlock(sem->mutex);
return 0;
}
static int sem_wait(sem_t *sem)
{
- mutex_lock(&sem->mutex);
+ Mutex_lock(sem->mutex);
while (sem->value == 0) {
+#error We cannot call pthread_cond_wait on a Mutex-class pointer.
pthread_cond_wait(&sem->cond, &sem->mutex);
}
sem->value--;
- mutex_unlock(&sem->mutex);
+ Mutex_unlock(sem->mutex);
return 0;
}
if (pthread_cond_destroy(&sem->cond) < 0)
return -1;
- mutex_destroy(&sem->mutex);
+ Mutex_destroy(sem->mutex);
return 0;
}
#endif /* defined(__DARWIN__) */
-/* internally used constants **************************************************/
-
-/* CAUTION: Do not change these values. Boehm GC code depends on them. */
-#define STOPWORLD_FROM_GC 1
-#define STOPWORLD_FROM_CLASS_NUMBERING 2
-
-
/* startupinfo *****************************************************************
Struct used to pass info from threads_start_thread to
#endif
/* global mutex for stop-the-world */
-static mutex_t stopworldlock;
+static Mutex* stopworldlock;
#if defined(ENABLE_GC_CACAO)
/* global mutex for the GC */
-static mutex_t mutex_gc;
+static Mutex* mutex_gc;
#endif
/* global mutex and condition for joining threads on exit */
-static 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 1
-
-/* this is one of the STOPWORLD_FROM_ constants, telling why the world is */
-/* being stopped */
-static volatile int stopworldwhere;
+static Mutex* mutex_join;
+static Condition* cond_join;
+#if defined(ENABLE_GC_CACAO)
/* semaphore used for acknowleding thread suspension */
static sem_t suspend_ack;
-#if defined(__IRIX__)
-static mutex_t suspend_ack_lock = 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)
-mutex_t _cas_lock = MUTEX_INITIALIZER;
-mutex_t _mb_lock = MUTEX_INITIALIZER;
#endif
}
-/* lock_stopworld **************************************************************
-
- Enter the stopworld lock, specifying why the world shall be stopped.
-
- IN:
- where........ STOPWORLD_FROM_GC (1) from within GC
- STOPWORLD_FROM_CLASS_NUMBERING (2) class numbering
-
-******************************************************************************/
-
-void lock_stopworld(int where)
-{
- mutex_lock(&stopworldlock);
-/* stopworldwhere = where; */
-}
-
-
-/* unlock_stopworld ************************************************************
-
- Release the stopworld lock.
-
-******************************************************************************/
-
-void unlock_stopworld(void)
-{
-/* stopworldwhere = 0; */
- 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)
-{
- threadobject *t;
- threadobject *self;
- s4 count;
-
- self = THREADOBJECT;
-
- /* iterate over all started threads */
-
- count = 0;
-
- for (t = threadlist_first(); t != NULL; t = threadlist_next(t)) {
- /* don't send the signal to ourself */
-
- if (t == self)
- continue;
-
- /* don't send the signal to NEW threads (because they are not
- completely initialized) */
-
- if (t->state == THREAD_STATE_NEW)
- continue;
-
- /* send the signal */
-
- pthread_kill(t->tid, sig);
-
- /* increase threads count */
-
- count++;
- }
-
- return count;
-}
-
-#else
-
-static void threads_cast_darwinstop(void)
-{
- threadobject *tobj = mainthreadobj;
- threadobject *self = THREADOBJECT;
-
- do {
- if (tobj != self)
- {
- thread_state_flavor_t flavor = MACHINE_THREAD_STATE;
- mach_msg_type_number_t thread_state_count = MACHINE_THREAD_STATE_COUNT;
-#if defined(__I386__)
- i386_thread_state_t thread_state;
-#else
- ppc_thread_state_t thread_state;
-#endif
- mach_port_t thread = tobj->mach_thread;
- kern_return_t r;
-
- r = thread_suspend(thread);
-
- if (r != KERN_SUCCESS)
- vm_abort("thread_suspend failed");
-
- r = thread_get_state(thread, flavor, (natural_t *) &thread_state,
- &thread_state_count);
-
- if (r != KERN_SUCCESS)
- vm_abort("thread_get_state failed");
-
- md_critical_section_restart((ucontext_t *) &thread_state);
-
- r = thread_set_state(thread, flavor, (natural_t *) &thread_state,
- thread_state_count);
-
- if (r != KERN_SUCCESS)
- vm_abort("thread_set_state failed");
- }
-
- tobj = tobj->next;
- } while (tobj != mainthreadobj);
-}
-
-static void threads_cast_darwinresume(void)
-{
- threadobject *tobj = mainthreadobj;
- threadobject *self = THREADOBJECT;
-
- do {
- if (tobj != self)
- {
- mach_port_t thread = tobj->mach_thread;
- kern_return_t r;
-
- r = thread_resume(thread);
-
- if (r != KERN_SUCCESS)
- vm_abort("thread_resume failed");
- }
-
- tobj = tobj->next;
- } while (tobj != mainthreadobj);
-}
-
-#endif
-
-#if defined(__IRIX__)
-static void threads_cast_irixresume(void)
-{
- mutex_lock(&suspend_ack_lock);
- pthread_cond_broadcast(&suspend_cond);
- mutex_unlock(&suspend_ack_lock);
-}
-#endif
-
-#if defined(ENABLE_GC_BOEHM) && !defined(__DARWIN__)
-static void threads_sigsuspend_handler(ucontext_t *_uc)
-{
- int sig;
- sigset_t sigs;
-
- /* XXX TWISTI: this is just a quick hack */
-#if defined(ENABLE_JIT)
- md_critical_section_restart(_uc);
-#endif
-
- /* Do as Boehm does. On IRIX a condition variable is used for wake-up
- (not POSIX async-safe). */
-#if defined(__IRIX__)
- mutex_lock(&suspend_ack_lock);
- threads_sem_post(&suspend_ack);
- pthread_cond_wait(&suspend_cond, &suspend_ack_lock);
- mutex_unlock(&suspend_ack_lock);
-#elif defined(__CYGWIN__)
- /* TODO */
- assert(0);
-#else
-
- sig = GC_signum2();
- sigfillset(&sigs);
- sigdelset(&sigs, sig);
- sigsuspend(&sigs);
-#endif
-}
-#endif
-
-#endif
-
-
/* threads_stopworld ***********************************************************
Stops the world from turning. All threads except the calling one
*******************************************************************************/
-#if !defined(DISABLE_GC)
+#if defined(ENABLE_GC_CACAO)
void threads_stopworld(void)
{
#if !defined(__DARWIN__) && !defined(__CYGWIN__)
s4 count, i;
#endif
- lock_stopworld(STOPWORLD_FROM_CLASS_NUMBERING);
+ Mutex_lock(stopworldlock);
/* lock the threads lists */
non-signaled NEW threads can't change their state and execute
code. */
}
-#endif /* !defined(DISABLE_GC) */
+#endif
/* threads_startworld **********************************************************
*******************************************************************************/
-#if !defined(DISABLE_GC)
+#if defined(ENABLE_GC_CACAO)
void threads_startworld(void)
{
#if !defined(__DARWIN__) && !defined(__CYGWIN__)
threadlist_unlock();
- unlock_stopworld();
+ Mutex_unlock(stopworldlock);
}
#endif
void threads_impl_thread_init(threadobject *t)
{
- int result;
-
/* initialize the mutex and the condition */
- mutex_init(&t->flc_lock);
+ t->flc_lock = Mutex_new();
+ t->flc_cond = Condition_new();
- result = pthread_cond_init(&t->flc_cond, NULL);
- if (result != 0)
- vm_abort_errnum(result, "threads_impl_thread_new: pthread_cond_init failed");
-
- mutex_init(&(t->waitmutex));
+ t->waitmutex = Mutex_new();
+ t->waitcond = Condition_new();
- result = pthread_cond_init(&(t->waitcond), NULL);
- if (result != 0)
- vm_abort_errnum(result, "threads_impl_thread_new: pthread_cond_init failed");
+ t->suspendmutex = Mutex_new();
+ t->suspendcond = Condition_new();
- mutex_init(&(t->suspendmutex));
-
- result = pthread_cond_init(&(t->suspendcond), NULL);
- if (result != 0)
- vm_abort_errnum(result, "threads_impl_thread_new: pthread_cond_init failed");
+#if defined(ENABLE_TLH)
+ tlh_init(&(t->tlh));
+#endif
}
/* threads_impl_thread_clear ***************************************************
t->interrupted = false;
t->signaled = false;
- t->sleeping = false;
t->suspended = false;
t->suspend_reason = 0;
/* not really needed */
t->flc_object = NULL;
+
+#if defined(ENABLE_TLH)
+ tlh_destroy(&(t->tlh));
+ tlh_init(&(t->tlh));
+#endif
}
/* Destroy the mutex and the condition. */
- mutex_destroy(&(t->flc_lock));
+ Mutex_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");
- mutex_destroy(&(t->waitmutex));
+ Mutex_delete(t->waitmutex);
result = pthread_cond_destroy(&(t->waitcond));
if (result != 0)
vm_abort_errnum(result, "threads_impl_thread_free: pthread_cond_destroy failed");
- mutex_destroy(&(t->suspendmutex));
+ Mutex_delete(t->suspendmutex);
result = pthread_cond_destroy(&(t->suspendcond));
{
int result;
- mutex_init(&stopworldlock);
+ stopworldlock = Mutex_new();
/* initialize exit mutex and condition (on exit we join all
threads) */
- mutex_init(&mutex_join);
-
- result = pthread_cond_init(&cond_join, NULL);
- if (result != 0)
- vm_abort_errnum(result, "threads_impl_preinit: pthread_cond_init failed");
+ mutex_join = Mutex_new();
+ cond_join = Condition_new();
#if defined(ENABLE_GC_CACAO)
- /* initialize the GC mutext */
+ /* initialize the GC mutex & suspend semaphore */
- mutex_init(&mutex_gc);
+ mutex_gc = Mutex_new();
+ threads_sem_init(&suspend_ack, 0, 0);
#endif
#if !defined(HAVE___THREAD)
if (result != 0)
vm_abort_errnum(result, "threads_impl_preinit: pthread_key_create failed");
#endif
-
- threads_sem_init(&suspend_ack, 0, 0);
}
#if defined(ENABLE_GC_CACAO)
void threads_mutex_gc_lock(void)
{
- mutex_lock(&mutex_gc);
+ Mutex_lock(mutex_gc);
}
#endif
#if defined(ENABLE_GC_CACAO)
void threads_mutex_gc_unlock(void)
{
- mutex_unlock(&mutex_gc);
+ Mutex_unlock(mutex_gc);
}
#endif
void threads_mutex_join_lock(void)
{
- mutex_lock(&mutex_join);
+ Mutex_lock(mutex_join);
}
void threads_mutex_join_unlock(void)
{
- mutex_unlock(&mutex_join);
+ Mutex_unlock(mutex_join);
}
startupinfo *startup;
threadobject *t;
java_lang_Thread *object;
-#if defined(WITH_CLASSPATH_GNU)
+#if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
java_lang_VMThread *vmt;
#endif
sem_t *psem;
java_handle_t *o;
functionptr function;
+#if defined(ENABLE_GC_BOEHM)
+# if !defined(__DARWIN__)
+ struct GC_stack_base sb;
+ int result;
+# endif
+#endif
+
#if defined(ENABLE_INTRP)
u1 *intrp_thread_stack;
+#endif
+#if defined(ENABLE_INTRP)
/* create interpreter stack */
if (opt_intrp) {
thread_set_current(t);
+#if defined(ENABLE_GC_BOEHM)
+# if defined(__DARWIN__)
+ // This is currently not implemented in Boehm-GC. Just fail silently.
+# else
+ /* 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 != 0)
+ vm_abort("threads_startup_thread: GC_get_stack_base failed: result=%d", result);
+
+ GC_register_my_thread(&sb);
+# endif
+#endif
+
/* get the java.lang.Thread object for this thread */
object = (java_lang_Thread *) thread_get_object(t);
/* find and run the Thread.run()V method if no other function was passed */
if (function == NULL) {
-#if defined(WITH_CLASSPATH_GNU)
+#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_CLASSPATH_SUN) || defined(WITH_CLASSPATH_CLDC1_1)
+#elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK) || defined(WITH_JAVA_RUNTIME_LIBRARY_CLDC1_1)
LLNI_class_get(object, c);
#else
# error unknown classpath configuration
_Jv_jvm->java_lang_management_ThreadMXBean_PeakThreadCount =
_Jv_jvm->java_lang_management_ThreadMXBean_ThreadCount;
-#if defined(WITH_CLASSPATH_GNU)
+#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_CLASSPATH_SUN) || defined(WITH_CLASSPATH_CLDC1_1)
+#elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK) || defined(WITH_JAVA_RUNTIME_LIBRARY_CLDC1_1)
o = (java_handle_t *) object;
#else
# error unknown classpath configuration
/* We ignore the return value. */
- (void) threads_detach_thread(t);
+ (void) thread_detach_current_thread();
/* set ThreadMXBean variables */
}
-/* threads_detach_thread *******************************************************
-
- Detaches the passed thread from the VM. Used in JNI.
-
-*******************************************************************************/
-
-bool threads_detach_thread(threadobject *t)
+/**
+ * Detaches the current thread from the VM.
+ *
+ * @return true on success, false otherwise
+ */
+bool thread_detach_current_thread(void)
{
+ threadobject *t;
bool result;
java_lang_Thread *object;
java_handle_t *o;
methodinfo *m;
#endif
+ t = thread_get_current();
+
+ /* Sanity check. */
+
+ assert(t != NULL);
+
/* If the given thread has already been detached, this operation
is a no-op. */
to build the java_lang_Thread_UncaughtExceptionHandler
header file with cacaoh. */
-# if defined(WITH_CLASSPATH_GNU)
+# if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
LLNI_field_get_ref(object, exceptionHandler, handler);
-# elif defined(WITH_CLASSPATH_SUN)
+# elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
LLNI_field_get_ref(object, uncaughtExceptionHandler, handler);
# endif
if (group != NULL) {
LLNI_class_get(group, c);
-# if defined(WITH_CLASSPATH_GNU)
+# 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_CLASSPATH_SUN)
+# elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
m = class_resolveclassmethod(c,
utf_remove,
utf_java_lang_Thread__V,
/* Signal that this thread has finished and leave the mutex. */
- pthread_cond_signal(&cond_join);
+ Condition_signal(cond_join);
threads_mutex_join_unlock();
return true;
bool threads_suspend_thread(threadobject *thread, s4 reason)
{
/* acquire the suspendmutex */
- mutex_lock(&(thread->suspendmutex));
+ Mutex_lock(thread->suspendmutex);
if (thread->suspended) {
- mutex_unlock(&(thread->suspendmutex));
+ Mutex_unlock(thread->suspendmutex);
return false;
}
*******************************************************************************/
+#if defined(ENABLE_GC_CACAO)
void threads_suspend_ack(u1* pc, u1* sp)
{
threadobject *thread;
/* TODO: remember dump memory size */
-#if defined(ENABLE_GC_CACAO)
/* inform the GC about the suspension */
if (thread->suspend_reason == SUSPEND_REASON_STOPWORLD && gc_pending) {
}
}
-#endif
/* mark this thread as suspended and remember the PC */
thread->pc = pc;
DEBUGTHREADS("suspending", thread);
/* release the suspension mutex and wait till we are resumed */
- pthread_cond_wait(&(thread->suspendcond), &(thread->suspendmutex));
+ Condition_wait(thread->suspendcond, thread->suspendmutex);
DEBUGTHREADS("resuming", thread);
/* TODO: free dump memory */
/* release the suspendmutex */
- mutex_unlock(&(thread->suspendmutex));
+ Mutex_unlock(thread->suspendmutex);
}
+#endif
/* threads_resume_thread *******************************************************
*******************************************************************************/
+#if defined(ENABLE_GC_CACAO)
bool threads_resume_thread(threadobject *thread)
{
/* acquire the suspendmutex */
- mutex_lock(&(thread->suspendmutex));
+ Mutex_lock(thread->suspendmutex);
if (!thread->suspended) {
- mutex_unlock(&(thread->suspendmutex));
+ Mutex_unlock(thread->suspendmutex);
return false;
}
/* tell everyone that the thread should resume */
assert(thread != THREADOBJECT);
- pthread_cond_broadcast(&(thread->suspendcond));
+ Condition_broadcast(thread->suspendcond);
/* release the suspendmutex */
- mutex_unlock(&(thread->suspendmutex));
+ Mutex_unlock(thread->suspendmutex);
return true;
}
+#endif
/* threads_join_all_threads ****************************************************
non-daemon thread. */
while (threadlist_get_non_daemons() > 1)
- pthread_cond_wait(&cond_join, &mutex_join);
+ Condition_wait(cond_join, mutex_join);
/* leave join mutex */
{
/* acquire the waitmutex */
- mutex_lock(&t->waitmutex);
-
- /* mark us as sleeping */
-
- t->sleeping = true;
+ Mutex_lock(t->waitmutex);
/* wait on waitcond */
{
thread_set_state_timed_waiting(t);
- pthread_cond_timedwait(&t->waitcond, &t->waitmutex,
- wakeupTime);
+ Condition_timedwait(t->waitcond, t->waitmutex, wakeupTime);
thread_set_state_runnable(t);
}
while (!t->interrupted && !t->signaled) {
thread_set_state_waiting(t);
- pthread_cond_wait(&t->waitcond, &t->waitmutex);
+ Condition_wait(t->waitcond, t->waitmutex);
thread_set_state_runnable(t);
}
}
- t->sleeping = false;
-
/* release the waitmutex */
- mutex_unlock(&t->waitmutex);
+ Mutex_unlock(t->waitmutex);
}
void threads_thread_interrupt(threadobject *thread)
{
+#if defined(__LINUX__) && defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
+ /* See openjdk/jdk/src/solaris/native/java/net/linux_close.c, "sigWakeup" */
+ int sig = (__SIGRTMAX - 2);
+#else
+ int sig = SIGHUP;
+#endif
/* Signal the thread a "waitcond" and tell it that it has been
interrupted. */
- mutex_lock(&thread->waitmutex);
+ Mutex_lock(thread->waitmutex);
DEBUGTHREADS("interrupted", thread);
/* Interrupt blocking system call using a signal. */
- pthread_kill(thread->tid, SIGHUP);
+ pthread_kill(thread->tid, sig);
- if (thread->sleeping)
- pthread_cond_signal(&thread->waitcond);
+ Condition_signal(thread->waitcond);
thread->interrupted = true;
- mutex_unlock(&thread->waitmutex);
+ Mutex_unlock(thread->waitmutex);
}
sched_yield();
}
+#if defined(ENABLE_TLH)
+
+void threads_tlh_add_frame() {
+ tlh_add_frame(&(THREADOBJECT->tlh));
+}
+
+void threads_tlh_remove_frame() {
+ tlh_remove_frame(&(THREADOBJECT->tlh));
+}
+
+#endif
/*
* These are local overrides for various environment variables in Emacs.