/* src/threads/thread.cpp - machine independent thread functions
- Copyright (C) 2007, 2008
+ Copyright (C) 1996-2011
CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
This file is part of CACAO.
#include "vm/types.h"
-#include "mm/memory.h"
+#include "mm/memory.hpp"
#if defined(ENABLE_GC_BOEHM)
/* We need to include Boehm's gc.h here for GC_register_my_thread and
/* static functions ***********************************************************/
-static void thread_create_initial_threadgroups(void);
static void thread_create_initial_thread(void);
-static threadobject *thread_new(void);
+static threadobject *thread_new(int32_t flags);
/* threads_preinit *************************************************************
/* Create internal thread data-structure for the main thread. */
- mainthread = thread_new();
+ mainthread = thread_new(THREAD_FLAG_JAVA);
/* The main thread should always have index 1. */
vm_abort("threads_preinit: main thread index not 1: %d != 1",
mainthread->index);
- /* thread is a Java thread and running */
+ /* Thread is already running. */
- mainthread->flags |= THREAD_FLAG_JAVA;
mainthread->state = THREAD_STATE_RUNNABLE;
/* Store the internal thread data-structure in the TSD. */
/* Create the system and main thread groups. */
- thread_create_initial_threadgroups();
+ ThreadRuntime::thread_create_initial_threadgroups(&threadgroup_main, &threadgroup_system);
/* Cache the java.lang.Thread initialization method. */
-#if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
-
- thread_method_init =
- class_resolveclassmethod(class_java_lang_Thread,
- utf_init,
- utf_new_char("(Ljava/lang/VMThread;Ljava/lang/String;IZ)V"),
- class_java_lang_Thread,
- true);
-
-#elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
-
- thread_method_init =
- class_resolveclassmethod(class_java_lang_Thread,
- utf_init,
- utf_new_char("(Ljava/lang/ThreadGroup;Ljava/lang/String;)V"),
- class_java_lang_Thread,
- true);
-
-#elif defined(WITH_JAVA_RUNTIME_LIBRARY_CLDC1_1)
-
- thread_method_init =
- class_resolveclassmethod(class_java_lang_Thread,
- utf_init,
- utf_java_lang_String__void,
- class_java_lang_Thread,
- true);
-
-#else
-# error unknown classpath configuration
-#endif
+ thread_method_init = ThreadRuntime::get_thread_init_method();
if (thread_method_init == NULL)
vm_abort("threads_init: failed to resolve thread init method");
// indicates that the thread is attached to the VM.
thread_set_object(t, jlt.get_handle());
-#if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
-
- h = builtin_new(class_java_lang_VMThread);
-
- if (h == NULL)
- return false;
-
- // Create and initialize a java.lang.VMThread object.
- java_lang_VMThread jlvmt(h, jlt.get_handle(), t);
-
- /* Call:
- java.lang.Thread.<init>(Ljava/lang/VMThread;Ljava/lang/String;IZ)V */
-
- bool isdaemon = thread_is_daemon(t);
-
- (void) vm_call_method(thread_method_init, jlt.get_handle(), jlvmt.get_handle(),
- name, NORM_PRIORITY, isdaemon);
-
- if (exceptions_get_exception())
- return false;
-
- // Set the ThreadGroup in the Java thread object.
- jlt.set_group(group);
-
- /* Add thread to the threadgroup. */
-
- classinfo* c;
- LLNI_class_get(group, c);
-
- methodinfo* m = class_resolveclassmethod(c,
- utf_addThread,
- utf_java_lang_Thread__V,
- class_java_lang_ThreadGroup,
- true);
-
- if (m == NULL)
- return false;
-
- (void) vm_call_method(m, group, jlt.get_handle());
-
- if (exceptions_get_exception())
- return false;
-
-#elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
-
- /* Set the priority. java.lang.Thread.<init> requires it because
- it sets the priority of the current thread to the parent's one
- (which is the current thread in this case). */
- jlt.set_priority(NORM_PRIORITY);
-
- // Call: java.lang.Thread.<init>(Ljava/lang/ThreadGroup;Ljava/lang/String;)V
-
- (void) vm_call_method(thread_method_init, jlt.get_handle(), group, name);
-
- if (exceptions_get_exception())
- return false;
-
-#elif defined(WITH_JAVA_RUNTIME_LIBRARY_CLDC1_1)
-
- // Set the thread data-structure in the Java thread object.
- jlt.set_vm_thread(t);
-
- // Call: public Thread(Ljava/lang/String;)V
- (void) vm_call_method(thread_method_init, jlt.get_handle(), name);
-
- if (exceptions_get_exception())
- return false;
-
-#else
-# error unknown classpath configuration
-#endif
-
- return true;
-}
-
-
-/* thread_create_initial_threadgroups ******************************************
-
- Create the initial threadgroups.
-
- GNU Classpath:
- Create the main threadgroup only and set the system
- threadgroup to the main threadgroup.
-
- SUN:
- Create the system and main threadgroup.
-
- CLDC:
- This function is a no-op.
-
-*******************************************************************************/
-
-static void thread_create_initial_threadgroups(void)
-{
-#if defined(ENABLE_JAVASE)
-# if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
-
- /* Allocate and initialize the main thread group. */
-
- threadgroup_main = native_new_and_init(class_java_lang_ThreadGroup);
-
- if (threadgroup_main == NULL)
- vm_abort("thread_create_initial_threadgroups: failed to allocate main threadgroup");
-
- /* Use the same threadgroup for system as for main. */
-
- threadgroup_system = threadgroup_main;
-
-# elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
-
- java_handle_t *name;
- methodinfo *m;
-
- /* Allocate and initialize the system thread group. */
-
- threadgroup_system = native_new_and_init(class_java_lang_ThreadGroup);
-
- if (threadgroup_system == NULL)
- vm_abort("thread_create_initial_threadgroups: failed to allocate system threadgroup");
-
- /* Allocate and initialize the main thread group. */
-
- threadgroup_main = builtin_new(class_java_lang_ThreadGroup);
-
- if (threadgroup_main == NULL)
- vm_abort("thread_create_initial_threadgroups: failed to allocate main threadgroup");
-
- name = javastring_new(utf_main);
-
- m = class_resolveclassmethod(class_java_lang_ThreadGroup,
- utf_init,
- utf_Ljava_lang_ThreadGroup_Ljava_lang_String__V,
- class_java_lang_ThreadGroup,
- true);
-
- if (m == NULL)
- vm_abort("thread_create_initial_threadgroups: failed to resolve threadgroup init method");
-
- (void) vm_call_method(m, threadgroup_main, threadgroup_system, name);
-
- if (exceptions_get_exception())
- vm_abort("thread_create_initial_threadgroups: exception while initializing main threadgroup");
-
-# else
-# error unknown classpath configuration
-# endif
-#endif
+ return ThreadRuntime::invoke_thread_initializer(jlt, t, thread_method_init, name, group);
}
*******************************************************************************/
-static threadobject *thread_new(void)
+static threadobject *thread_new(int32_t flags)
{
int32_t index;
threadobject *t;
t->index = index;
t->thinlock = Lockword::pre_compute_thinlock(t->index);
- t->flags = 0;
+ t->flags = flags;
t->state = THREAD_STATE_NEW;
#if defined(ENABLE_GC_CACAO)
/* Create internal thread data-structure. */
- t = thread_new();
-
- t->flags |= THREAD_FLAG_INTERNAL | THREAD_FLAG_DAEMON;
+ t = thread_new(THREAD_FLAG_INTERNAL | THREAD_FLAG_DAEMON);
/* The thread is flagged as (non-)daemon thread, we can leave the
mutex. */
/* Create internal thread data-structure. */
- threadobject* t = thread_new();
-
- /* this is a normal Java thread */
-
- t->flags |= THREAD_FLAG_JAVA;
+ threadobject* t = thread_new(THREAD_FLAG_JAVA);
#if defined(ENABLE_JAVASE)
/* Is this a daemon thread? */
thread_set_object(t, object);
-#if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
-
- /* Get the java.lang.VMThread object and do some sanity checks. */
- java_lang_VMThread jlvmt(jlt.get_vmThread());
-
- assert(jlvmt.get_handle() != NULL);
- assert(jlvmt.get_vmdata() == NULL);
-
- jlvmt.set_vmdata(t);
-
-#elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
-
- // Nothing to do.
-
-#elif defined(WITH_JAVA_RUNTIME_LIBRARY_CLDC1_1)
-
- jlt.set_vm_thread(t);
-
-#else
-# error unknown classpath configuration
-#endif
+ ThreadRuntime::setup_thread_vmdata(jlt, t);
/* Start the thread. Don't pass a function pointer (NULL) since
we want Thread.run()V here. */
/* Create internal thread data structure. */
- t = thread_new();
-
- /* Thread is a Java thread and running. */
-
- t->flags = THREAD_FLAG_JAVA;
+ t = thread_new(THREAD_FLAG_JAVA);
if (isdaemon)
t->flags |= THREAD_FLAG_DAEMON;
#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.*/
the thread allocates any memory from the GC heap. */
/* Don't detach the main thread. This is a workaround for
- OpenJDK's java binary. */
+ OpenJDK's java launcher. */
if (thread_get_current()->index != 1)
GC_unregister_my_thread();
#endif
java_lang_Thread jlt(thread_get_object(t));
-#if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
-
- java_handle_t* name = jlt.get_name();
- javastring_fprint(name, stream);
-
-#elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK) || defined(WITH_JAVA_RUNTIME_LIBRARY_CLDC1_1)
-
- /* FIXME: In OpenJDK and CLDC the name is a char[]. */
- //java_chararray_t *name;
-
- /* FIXME This prints to stdout. */
- utf_display_printable_ascii(utf_null);
-
-#else
-# error unknown classpath configuration
-#endif
+ ThreadRuntime::print_thread_name(jlt, stream);
}
case THREAD_STATE_TIMED_WAITING:
printf(" waiting on condition");
break;
+ case THREAD_STATE_PARKED:
+ printf(" parked");
+ break;
+ case THREAD_STATE_TIMED_PARKED:
+ printf(" timed parked");
+ break;
case THREAD_STATE_TERMINATED:
printf(" terminated");
break;
}
+/**
+ * Set the current state of the given thread. This method should only
+ * be called while holding the threadlist-lock and after checking that
+ * the new state is valid. It is best to not call this method directly
+ * but call the specific setter methods below.
+ */
+static inline void thread_set_state(threadobject *t, int state)
+{
+ // Set the state of our internal threadobject.
+ t->state = state;
+
+ ThreadRuntime::set_javathread_state(t, state);
+}
+
+
/* thread_set_state_runnable ***************************************************
Set the current state of the given thread to THREAD_STATE_RUNNABLE.
void thread_set_state_runnable(threadobject *t)
{
- /* Set the state inside a lock. */
-
- ThreadList::lock();
-
if (t->state != THREAD_STATE_TERMINATED) {
- t->state = THREAD_STATE_RUNNABLE;
+ thread_set_state(t, THREAD_STATE_RUNNABLE);
DEBUGTHREADS("is RUNNABLE", t);
}
-
- ThreadList::unlock();
}
void thread_set_state_waiting(threadobject *t)
{
- /* Set the state inside a lock. */
-
- ThreadList::lock();
-
if (t->state != THREAD_STATE_TERMINATED) {
- t->state = THREAD_STATE_WAITING;
+ thread_set_state(t, THREAD_STATE_WAITING);
DEBUGTHREADS("is WAITING", t);
}
-
- ThreadList::unlock();
}
void thread_set_state_timed_waiting(threadobject *t)
{
- /* Set the state inside a lock. */
+ if (t->state != THREAD_STATE_TERMINATED) {
+ thread_set_state(t, THREAD_STATE_TIMED_WAITING);
- ThreadList::lock();
+ DEBUGTHREADS("is TIMED_WAITING", t);
+ }
+}
+
+
+/* thread_set_state_parked *****************************************************
+
+ Set the current state of the given thread to THREAD_STATE_PARKED.
+
+ NOTE: If the thread has already terminated, don't set the state.
+ This is important for threads_detach_thread.
+
+*******************************************************************************/
+void thread_set_state_parked(threadobject *t)
+{
if (t->state != THREAD_STATE_TERMINATED) {
- t->state = THREAD_STATE_TIMED_WAITING;
+ thread_set_state(t, THREAD_STATE_PARKED);
- DEBUGTHREADS("is TIMED_WAITING", t);
+ DEBUGTHREADS("is PARKED", t);
}
+}
- ThreadList::unlock();
+
+/* thread_set_state_timed_parked ***********************************************
+
+ Set the current state of the given thread to THREAD_STATE_TIMED_PARKED.
+
+ NOTE: If the thread has already terminated, don't set the state.
+ This is important for threads_detach_thread.
+
+*******************************************************************************/
+
+void thread_set_state_timed_parked(threadobject *t)
+{
+ if (t->state != THREAD_STATE_TERMINATED) {
+ thread_set_state(t, THREAD_STATE_TIMED_PARKED);
+
+ DEBUGTHREADS("is TIMED_PARKED", t);
+ }
}
ThreadList::lock();
- t->state = THREAD_STATE_TERMINATED;
+ thread_set_state(t, THREAD_STATE_TERMINATED);
DEBUGTHREADS("is TERMINATED", t);
RETURN VALUE:
the thread object
+ NOTE:
+ Usage of this function without the thread list lock held is
+ almost certainly a bug.
+
*******************************************************************************/
threadobject *thread_get_thread(java_handle_t *h)
{
-#if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
-
- java_lang_VMThread jlvmt(h);
- threadobject* t = jlvmt.get_vmdata();
-
-#elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
-
- /* XXX This is just a quick hack. */
- threadobject* t = ThreadList::get_thread_from_java_object(h);
-
-#elif defined(WITH_JAVA_RUNTIME_LIBRARY_CLDC1_1)
-
- log_println("thread_get_thread: IMPLEMENT ME!");
- threadobject* t = NULL;
-
-#else
-# error unknown classpath configuration
-#endif
-
- return t;
+ return ThreadRuntime::get_threadobject_from_thread(h);
}
case THREAD_STATE_BLOCKED:
case THREAD_STATE_WAITING:
case THREAD_STATE_TIMED_WAITING:
+ case THREAD_STATE_PARKED:
+ case THREAD_STATE_TIMED_PARKED:
return true;
default:
return false;
}
+/* thread_is_interrupted *******************************************************
+
+ Check if the given thread has been interrupted.
+
+ ARGUMENTS:
+ t ... the thread to check
+
+ RETURN VALUE:
+ true, if the given thread had been interrupted
+
+*******************************************************************************/
+
+bool thread_is_interrupted(threadobject *t)
+{
+ /* We need the mutex because classpath will call this function when
+ a blocking system call is interrupted. The mutex ensures that it will
+ see the correct value for the interrupted flag. */
+
+ t->waitmutex->lock();
+ bool interrupted = t->interrupted;
+ t->waitmutex->unlock();
+
+ return interrupted;
+}
+
+
+/* thread_set_interrupted ******************************************************
+
+ Set the interrupted flag to the given value.
+
+ ARGUMENTS:
+ interrupted ... value to set
+
+*******************************************************************************/
+
+void thread_set_interrupted(threadobject *t, bool interrupted)
+{
+ t->waitmutex->lock();
+ t->interrupted = interrupted;
+ t->waitmutex->unlock();
+}
+
+/* thread_handle_set_priority **************************************************
+
+ Calls threads_set_thread_priority for the threadobject associated
+ with the thread indicated by handle th, while holding the thread
+ list lock.
+
+*******************************************************************************/
+
+void thread_handle_set_priority(java_handle_t *th, int priority)
+{
+ ThreadListLocker l;
+
+ threadobject *t = thread_get_thread(th);
+ /* For GNU classpath, this should not happen, because both
+ setPriority() and start() are synchronized. */
+ assert(t != 0);
+ threads_set_thread_priority(t->tid, priority);
+}
+
+/* thread_handle_is_interrupted ************************************************
+
+ Calls thread_is_interrupted for the threadobject associated with
+ the thread indicated by handle th, while holding the thread list
+ lock.
+
+*******************************************************************************/
+
+bool thread_handle_is_interrupted(java_handle_t *th)
+{
+ ThreadListLocker l;
+
+ threadobject *t = thread_get_thread(th);
+ return t ? thread_is_interrupted(t) : false;
+}
+
+/* thread_handle_interrupt *****************************************************
+
+ Calls threads_thread_interrupt for the threadobject associated with
+ the thread indicated by handle th, while holding the thread list
+ lock.
+
+*******************************************************************************/
+
+void thread_handle_interrupt(java_handle_t *th)
+{
+ ThreadListLocker l;
+
+ threadobject *t = thread_get_thread(th);
+ /* For GNU classpath, this should not happen, because both
+ interrupt() and start() are synchronized. */
+ assert(t != 0);
+ threads_thread_interrupt(t);
+}
+
+/* thread_handle_get_state *****************************************************
+
+ Calls cacaothread_get_state for the threadobject associated with
+ the thread indicated by handle th, while holding the thread list
+ lock.
+
+*******************************************************************************/
+
+int thread_handle_get_state(java_handle_t *th)
+{
+ ThreadListLocker l;
+
+ threadobject *t = thread_get_thread(th);
+ return t ? cacaothread_get_state(t) : THREAD_STATE_NEW;
+}
+
/*
* These are local overrides for various environment variables in Emacs.