Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.
- $Id: threads.c 7830 2007-04-26 11:14:39Z twisti $
-
*/
#include "mm/memory.h"
#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 "threads/native/threads.h"
-#include "toolbox/avl.h"
#include "toolbox/logging.h"
#include "vm/builtin.h"
/* GLOBAL VARIABLES */
/******************************************************************************/
-/* the main thread */
-threadobject *mainthreadobj;
-
static methodinfo *method_thread_init;
/* the thread object of the current thread */
pthread_key_t threads_current_threadobject_key;
#endif
-/* global mutex for changing the thread list */
-static pthread_mutex_t threadlistlock;
+/* global mutex for the threads table */
+static pthread_mutex_t mutex_threads_list;
/* global mutex for stop-the-world */
static pthread_mutex_t stopworldlock;
static pthread_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 0
+
/* this is one of the STOPWORLD_FROM_ constants, telling why the world is */
/* being stopped */
static volatile int stopworldwhere;
static pthread_cond_t suspend_cond = PTHREAD_COND_INITIALIZER;
#endif
-static pthread_attr_t threadattr;
+#endif /* 0 */
/* mutexes used by the fake atomic instructions */
#if defined(USE_FAKE_ATOMIC_INSTRUCTIONS)
void lock_stopworld(int where)
{
pthread_mutex_lock(&stopworldlock);
- stopworldwhere = where;
+/* stopworldwhere = where; */
}
void unlock_stopworld(void)
{
- stopworldwhere = 0;
+/* stopworldwhere = 0; */
pthread_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 int threads_cast_sendsignals(int sig, int count)
+static s4 threads_cast_sendsignals(s4 sig)
{
- /* Count threads */
- threadobject *tobj = mainthreadobj;
- threadobject *self = THREADOBJECT;
+ threadobject *t;
+ threadobject *self;
+ s4 count;
- if (count == 0) {
- do {
- count++;
- tobj = tobj->next;
- } while (tobj != mainthreadobj);
- }
+ self = THREADOBJECT;
- assert(tobj == mainthreadobj);
+ /* iterate over all started threads */
- do {
- if (tobj != self)
- pthread_kill(tobj->tid, sig);
- tobj = tobj->next;
- } while (tobj != mainthreadobj);
+ count = 0;
+
+ for (t = threads_list_first(); t != NULL; t = threads_list_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) */
- return count - 1;
+ if (t->state == THREAD_STATE_NEW)
+ continue;
+
+ /* send the signal */
+
+ pthread_kill(t->tid, sig);
+
+ /* increase threads count */
+
+ count++;
+ }
+
+ return count;
}
#else
if (r != KERN_SUCCESS)
vm_abort("thread_get_state failed");
- thread_restartcriticalsection((ucontext_t *) &thread_state);
+ md_critical_section_restart((ucontext_t *) &thread_state);
r = thread_set_state(thread, flavor, (natural_t *) &thread_state,
thread_state_count);
void threads_cast_stopworld(void)
{
#if !defined(__DARWIN__) && !defined(__CYGWIN__)
- int count, i;
+ s4 count, i;
#endif
lock_stopworld(STOPWORLD_FROM_CLASS_NUMBERING);
- pthread_mutex_lock(&threadlistlock);
+
+ /* lock the threads lists */
+
+ threads_list_lock();
#if defined(__DARWIN__)
threads_cast_darwinstop();
/* TODO */
assert(0);
#else
- count = threads_cast_sendsignals(GC_signum1(), 0);
+ /* send all threads the suspend signal */
+
+ count = threads_cast_sendsignals(GC_signum1());
+
+ /* wait for all threads signaled to suspend */
+
for (i = 0; i < count; i++)
threads_sem_wait(&suspend_ack);
#endif
- pthread_mutex_unlock(&threadlistlock);
+ /* ATTENTION: Don't unlock the threads-lists here so that
+ non-signaled NEW threads can't change their state and execute
+ code. */
}
+
void threads_cast_startworld(void)
{
- pthread_mutex_lock(&threadlistlock);
#if defined(__DARWIN__)
threads_cast_darwinresume();
#elif defined(__MIPS__)
/* TODO */
assert(0);
#else
- threads_cast_sendsignals(GC_signum2(), -1);
+ (void) threads_cast_sendsignals(GC_signum2());
#endif
- pthread_mutex_unlock(&threadlistlock);
+
+ /* unlock the threads lists */
+
+ threads_list_unlock();
+
unlock_stopworld();
}
#if !defined(__DARWIN__)
-static void threads_sigsuspend_handler(ucontext_t *ctx)
+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)
- thread_restartcriticalsection(ctx);
+ md_critical_section_restart(_uc);
#endif
/* Do as Boehm does. On IRIX a condition variable is used for wake-up
#endif
}
+#endif
+
+
/* This function is called from Boehm GC code. */
-int cacao_suspendhandler(ucontext_t *ctx)
+int cacao_suspendhandler(ucontext_t *_uc)
{
if (stopworldwhere != STOPWORLD_FROM_CLASS_NUMBERING)
return 0;
- threads_sigsuspend_handler(ctx);
+ threads_sigsuspend_handler(_uc);
return 1;
}
-#endif
#endif /* DISABLE_GC */
+#endif /* 0 */
+
/* threads_set_current_threadobject ********************************************
}
-/* threads_init_threadobject **************************************************
+/* threads_impl_thread_new *****************************************************
Initialize implementation fields of a threadobject.
IN:
- thread............the threadobject
+ t....the threadobject
-******************************************************************************/
+*******************************************************************************/
-void threads_init_threadobject(threadobject *thread)
+void threads_impl_thread_new(threadobject *t)
{
/* get the pthread id */
- thread->tid = pthread_self();
+ t->tid = pthread_self();
- thread->index = 0;
+ /* initialize the mutex and the condition */
- /* TODO destroy all those things */
+ pthread_mutex_init(&(t->waitmutex), NULL);
+ pthread_cond_init(&(t->waitcond), NULL);
- pthread_mutex_init(&(thread->waitmutex), NULL);
- pthread_cond_init(&(thread->waitcond), NULL);
+#if defined(ENABLE_DEBUG_FILTER)
+ /* Initialize filter counters */
+ t->filterverbosecallctr[0] = 0;
+ t->filterverbosecallctr[1] = 0;
+#endif
- thread->interrupted = false;
- thread->signaled = false;
- thread->sleeping = false;
+#if !defined(NDEBUG)
+ t->tracejavacallindent = 0;
+ t->tracejavacallcount = 0;
+#endif
+}
+
+
+/* threads_impl_thread_free ****************************************************
+
+ Cleanup thread stuff.
+
+ IN:
+ t....the threadobject
+
+*******************************************************************************/
+
+void threads_impl_thread_free(threadobject *t)
+{
+ /* destroy the mutex and the condition */
+
+ if (pthread_mutex_destroy(&(t->waitmutex)) != 0)
+ vm_abort("threads_impl_thread_free: pthread_mutex_destroy failed: %s",
+ strerror(errno));
+
+ if (pthread_cond_destroy(&(t->waitcond)) != 0)
+ vm_abort("threads_impl_thread_free: pthread_cond_destroy failed: %s",
+ strerror(errno));
}
void threads_impl_preinit(void)
{
- pthread_mutex_init(&threadlistlock, NULL);
pthread_mutex_init(&stopworldlock, NULL);
/* initialize exit mutex and condition (on exit we join all
pthread_mutex_init(&mutex_join, NULL);
pthread_cond_init(&cond_join, NULL);
+ /* initialize the threads-list mutex */
+
+ pthread_mutex_init(&mutex_threads_list, NULL);
+
#if !defined(HAVE___THREAD)
pthread_key_create(&threads_current_threadobject_key, NULL);
#endif
- /* create internal thread data-structure */
+/* threads_sem_init(&suspend_ack, 0, 0); */
+}
- mainthreadobj = threads_create_thread();
- mainthreadobj->object = NULL;
- mainthreadobj->index = 1;
- mainthreadobj->thinlock = lock_pre_compute_thinlock(mainthreadobj->index);
+/* threads_list_lock ***********************************************************
- /* store the internal thread data-structure in the TSD */
+ Enter the threads table mutex.
+
+ NOTE: We need this function as we can't use an internal lock for
+ the threads lists because the thread's lock is initialized in
+ threads_table_add (when we have the thread index), but we
+ already need the lock at the entry of the function.
- threads_set_current_threadobject(mainthreadobj);
-
- threads_sem_init(&suspend_ack, 0, 0);
+*******************************************************************************/
+
+void threads_list_lock(void)
+{
+ if (pthread_mutex_lock(&mutex_threads_list) != 0)
+ vm_abort("threads_list_lock: pthread_mutex_lock failed: %s",
+ strerror(errno));
+}
+
+
+/* threads_list_unlock *********************************************************
+
+ Leave the threads list mutex.
+
+*******************************************************************************/
+
+void threads_list_unlock(void)
+{
+ if (pthread_mutex_unlock(&mutex_threads_list) != 0)
+ vm_abort("threads_list_unlock: pthread_mutex_unlock failed: %s",
+ strerror(errno));
+}
+
+
+/* threads_mutex_join_lock *****************************************************
+
+ Enter the join mutex.
+
+*******************************************************************************/
+
+void threads_mutex_join_lock(void)
+{
+ if (pthread_mutex_lock(&mutex_join) != 0)
+ vm_abort("threads_mutex_join_lock: pthread_mutex_lock failed: %s",
+ strerror(errno));
+}
+
+
+/* threads_mutex_join_unlock ***************************************************
+
+ Leave the join mutex.
+
+*******************************************************************************/
+
+void threads_mutex_join_unlock(void)
+{
+ if (pthread_mutex_unlock(&mutex_join) != 0)
+ vm_abort("threads_mutex_join_unlock: pthread_mutex_unlock failed: %s",
+ strerror(errno));
}
bool threads_init(void)
{
- java_objectheader *threadname;
- java_lang_Thread *t;
- java_objectheader *o;
+ threadobject *mainthread;
+ java_handle_t *threadname;
+ java_lang_Thread *t;
+ java_handle_t *o;
#if defined(ENABLE_JAVASE)
java_lang_ThreadGroup *threadgroup;
java_lang_VMThread *vmt;
#endif
+ pthread_attr_t attr;
+
/* get methods we need in this file */
#if defined(WITH_CLASSPATH_GNU)
utf_new_char("(Ljava/lang/VMThread;Ljava/lang/String;IZ)V"),
class_java_lang_Thread,
true);
-#else
+#elif defined(WITH_CLASSPATH_SUN)
+ method_thread_init =
+ class_resolveclassmethod(class_java_lang_Thread,
+ utf_init,
+ utf_new_char("(Ljava/lang/String;)V"),
+ class_java_lang_Thread,
+ true);
+#elif defined(WITH_CLASSPATH_CLDC1_1)
method_thread_init =
class_resolveclassmethod(class_java_lang_Thread,
utf_init,
utf_new_char("(Ljava/lang/String;)V"),
class_java_lang_Thread,
true);
+#else
+# error unknown classpath configuration
#endif
if (method_thread_init == NULL)
return false;
+ /* Get the main-thread (NOTE: The main threads is always the first
+ thread in the list). */
+
+ mainthread = threads_list_first();
+
/* create a java.lang.Thread for the main thread */
t = (java_lang_Thread *) builtin_new(class_java_lang_Thread);
/* set the object in the internal data structure */
- mainthreadobj->object = t;
-
- /* thread is running */
-
- mainthreadobj->state = THREAD_STATE_RUNNABLE;
-
- mainthreadobj->next = mainthreadobj;
- mainthreadobj->prev = mainthreadobj;
-
- threads_table_add(mainthreadobj);
-
- /* mark main thread as Java thread */
-
- mainthreadobj->flags = THREAD_FLAG_JAVA;
+ mainthread->object = t;
#if defined(ENABLE_INTRP)
/* create interpreter stack */
if (opt_intrp) {
MSET(intrp_main_stack, 0, u1, opt_stacksize);
- mainthreadobj->_global_sp = (Cell*) (intrp_main_stack + opt_stacksize);
+ mainthread->_global_sp = (Cell*) (intrp_main_stack + opt_stacksize);
}
#endif
/* set the thread */
- vmt->thread = t;
- vmt->vmdata = (java_lang_Object *) mainthreadobj;
+ LLNI_field_set_ref(vmt, thread, t);
+ LLNI_field_set_val(vmt, vmdata, (java_lang_Object *) mainthread);
/* call java.lang.Thread.<init>(Ljava/lang/VMThread;Ljava/lang/String;IZ)V */
- o = (java_objectheader *) t;
+ o = (java_handle_t *) t;
(void) vm_call_method(method_thread_init, o, vmt, threadname, NORM_PRIORITY,
false);
+
+#elif defined(WITH_CLASSPATH_SUN)
+
+ /* We trick java.lang.Thread.<init>, which sets the priority of
+ the current thread to the parent's one. */
+
+ t->priority = NORM_PRIORITY;
+
+ /* Call java.lang.Thread.<init>(Ljava/lang/String;)V */
+
+ o = (java_object_t *) t;
+
+ (void) vm_call_method(method_thread_init, o, threadname);
+
#elif defined(WITH_CLASSPATH_CLDC1_1)
+
/* set the thread */
- t->vm_thread = (java_lang_Object *) mainthreadobj;
+ t->vm_thread = (java_lang_Object *) mainthread;
/* call public Thread(String name) */
- o = (java_objectheader *) t;
+ o = (java_handle_t *) t;
(void) vm_call_method(method_thread_init, o, threadname);
+#else
+# error unknown classpath configuration
#endif
- if (*exceptionptr)
+ if (exceptions_get_exception())
return false;
#if defined(ENABLE_JAVASE)
- t->group = threadgroup;
+ LLNI_field_set_ref(t, group, threadgroup);
+# if defined(WITH_CLASSPATH_GNU)
/* add main thread to java.lang.ThreadGroup */
m = class_resolveclassmethod(class_java_lang_ThreadGroup,
class_java_lang_ThreadGroup,
true);
- o = (java_objectheader *) threadgroup;
+ o = (java_handle_t *) threadgroup;
(void) vm_call_method(m, o, t);
- if (*exceptionptr)
+ if (exceptions_get_exception())
return false;
+# else
+# warning Do not know what to do here
+# endif
#endif
threads_set_thread_priority(pthread_self(), NORM_PRIORITY);
/* initialize the thread attribute object */
- if (pthread_attr_init(&threadattr)) {
- log_println("pthread_attr_init failed: %s", strerror(errno));
- return false;
- }
+ if (pthread_attr_init(&attr) != 0)
+ vm_abort("threads_init: pthread_attr_init failed: %s", strerror(errno));
- pthread_attr_setdetachstate(&threadattr, PTHREAD_CREATE_DETACHED);
+ if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) != 0)
+ vm_abort("threads_init: pthread_attr_setdetachstate failed: %s",
+ strerror(errno));
+
+#if !defined(NDEBUG)
+ if (opt_verbosethreads) {
+ printf("[Starting thread ");
+ threads_thread_print_info(mainthread);
+ printf("]\n");
+ }
+#endif
/* everything's ok */
threads_startup.
IN:
- t............the argument passed to pthread_create, ie. a pointer to
+ arg..........the argument passed to pthread_create, ie. a pointer to
a startupinfo struct. CAUTION: When the `psem` semaphore
is posted, the startupinfo struct becomes invalid! (It
is allocated on the stack of threads_start_thread.)
******************************************************************************/
-static void *threads_startup_thread(void *t)
+static void *threads_startup_thread(void *arg)
{
startupinfo *startup;
threadobject *thread;
java_lang_VMThread *vmt;
#endif
sem_t *psem;
- threadobject *tnext;
classinfo *c;
methodinfo *m;
- java_objectheader *o;
+ java_handle_t *o;
functionptr function;
#if defined(ENABLE_INTRP)
/* get passed startupinfo structure and the values in there */
- startup = t;
- t = NULL; /* make sure it's not used wrongly */
+ startup = arg;
thread = startup->thread;
function = startup->function;
psem = startup->psem;
- /* Seems like we've encountered a situation where thread->tid was not set by
- * pthread_create. We alleviate this problem by waiting for pthread_create
- * to return. */
+ /* Seems like we've encountered a situation where thread->tid was
+ not set by pthread_create. We alleviate this problem by waiting
+ for pthread_create to return. */
+
threads_sem_wait(startup->psem_first);
#if defined(__DARWIN__)
threads_set_current_threadobject(thread);
- /* thread is running */
-
- thread->state = THREAD_STATE_RUNNABLE;
-
- /* insert the thread into the threadlist and the threads table */
-
- pthread_mutex_lock(&threadlistlock);
+ /* set our priority */
- thread->prev = mainthreadobj;
- thread->next = tnext = mainthreadobj->next;
- mainthreadobj->next = thread;
- tnext->prev = thread;
+ threads_set_thread_priority(thread->tid, LLNI_field_direct(thread->object, priority));
- threads_table_add(thread);
+ /* thread is completely initialized */
- pthread_mutex_unlock(&threadlistlock);
+ threads_thread_state_runnable(thread);
/* tell threads_startup_thread that we registered ourselves */
/* CAUTION: *startup becomes invalid with this! */
startup = NULL;
threads_sem_post(psem);
- /* set our priority */
-
- threads_set_thread_priority(thread->tid, thread->object->priority);
-
#if defined(ENABLE_INTRP)
/* set interpreter stack */
jvmti_ThreadStartEnd(JVMTI_EVENT_THREAD_START);
#endif
+#if !defined(NDEBUG)
+ if (opt_verbosethreads) {
+ printf("[Starting thread ");
+ threads_thread_print_info(thread);
+ printf("]\n");
+ }
+#endif
+
/* find and run the Thread.run()V method if no other function was passed */
if (function == NULL) {
- /* this is a normal Java thread */
-
- thread->flags |= THREAD_FLAG_JAVA;
-
#if defined(WITH_CLASSPATH_GNU)
/* 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_CLDC1_1)
- c = thread->object->header.vftbl->class;
+ c = class_java_lang_VMThread;
+#elif defined(WITH_CLASSPATH_SUN) || defined(WITH_CLASSPATH_CLDC1_1)
+ c = thread->object->header.vftbl->class;
+#else
+# error unknown classpath configuration
#endif
m = class_resolveclassmethod(c, utf_run, utf_void__void, c, true);
#if defined(WITH_CLASSPATH_GNU)
/* we need to start the run method of java.lang.VMThread */
- vmt = (java_lang_VMThread *) thread->object->vmThread;
- o = (java_objectheader *) vmt;
+ vmt = (java_lang_VMThread *) LLNI_field_direct(thread->object, vmThread);
+ o = (java_handle_t *) vmt;
-#elif defined(WITH_CLASSPATH_CLDC1_1)
- o = (java_objectheader *) thread->object;
+#elif defined(WITH_CLASSPATH_SUN) || defined(WITH_CLASSPATH_CLDC1_1)
+ o = (java_handle_t *) thread->object;
+#else
+# error unknown classpath configuration
#endif
/* run the thread */
(void) vm_call_method(m, o);
}
else {
- /* this is an internal thread */
-
- thread->flags |= THREAD_FLAG_INTERNAL;
-
/* set ThreadMXBean variables */
_Jv_jvm->java_lang_management_ThreadMXBean_ThreadCount++;
(function)();
}
+#if !defined(NDEBUG)
+ if (opt_verbosethreads) {
+ printf("[Stopping thread ");
+ threads_thread_print_info(thread);
+ printf("]\n");
+ }
+#endif
+
#if defined(ENABLE_JVMTI)
/* fire thread end event */
jvmti_ThreadStartEnd(JVMTI_EVENT_THREAD_END);
#endif
- if (!threads_detach_thread(thread))
- vm_abort("threads_startup_thread: threads_detach_thread failed");
+ /* We ignore the return value. */
+
+ (void) threads_detach_thread(thread);
/* set ThreadMXBean variables */
}
-/* threads_start_thread ********************************************************
+/* threads_impl_thread_start ***************************************************
- Start a thread in the JVM. Both (vm internal and java) thread objects exist.
+ Start a thread in the JVM. Both (vm internal and java) thread
+ objects exist.
IN:
- thread.......the thread object
- function.....function to run in the new thread. NULL means that the
- "run" method of the object `t` should be called
+ thread....the thread object
+ f.........function to run in the new thread. NULL means that the
+ "run" method of the object `t` should be called
******************************************************************************/
-void threads_start_thread(threadobject *thread, functionptr function)
+void threads_impl_thread_start(threadobject *thread, functionptr f)
{
sem_t sem;
sem_t sem_first;
pthread_attr_t attr;
startupinfo startup;
+ int ret;
/* fill startupinfo structure passed by pthread_create to
* threads_startup_thread */
startup.thread = thread;
- startup.function = function; /* maybe we don't call Thread.run()V */
+ startup.function = f; /* maybe we don't call Thread.run()V */
startup.psem = &sem;
startup.psem_first = &sem_first;
threads_sem_init(&sem, 0, 0);
threads_sem_init(&sem_first, 0, 0);
- /* initialize thread attribute object */
+ /* initialize thread attributes */
+
+ if (pthread_attr_init(&attr) != 0)
+ vm_abort("threads_impl_thread_start: pthread_attr_init failed: %s",
+ strerror(errno));
- if (pthread_attr_init(&attr))
- vm_abort("pthread_attr_init failed: %s", strerror(errno));
+ if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) != 0)
+ vm_abort("threads_impl_thread_start: pthread_attr_setdetachstate failed: %s",
+ strerror(errno));
/* initialize thread stacksize */
if (pthread_attr_setstacksize(&attr, opt_stacksize))
- vm_abort("pthread_attr_setstacksize failed: %s", strerror(errno));
+ vm_abort("threads_impl_thread_start: pthread_attr_setstacksize failed: %s",
+ strerror(errno));
/* create the thread */
- if (pthread_create(&(thread->tid), &attr, threads_startup_thread, &startup))
- vm_abort("pthread_create failed: %s", strerror(errno));
+ ret = pthread_create(&(thread->tid), &attr, threads_startup_thread, &startup);
+
+ /* destroy the thread attributes */
+
+ if (pthread_attr_destroy(&attr) != 0)
+ vm_abort("threads_impl_thread_start: pthread_attr_destroy failed: %s",
+ strerror(errno));
+
+ /* check for pthread_create error */
+
+ if (ret != 0)
+ vm_abort("threads_impl_thread_start: pthread_create failed: %s",
+ strerror(errno));
/* signal that pthread_create has returned, so thread->tid is valid */
{
threadobject *thread;
utf *u;
- java_objectheader *s;
- java_objectheader *o;
+ java_handle_t *s;
+ java_handle_t *o;
java_lang_Thread *t;
#if defined(ENABLE_JAVASE)
java_lang_ThreadGroup *group;
+ threadobject *mainthread;
+ classinfo *c;
methodinfo *m;
#endif
java_lang_VMThread *vmt;
#endif
- /* create internal thread data-structure */
+ /* Enter the join-mutex, so if the main-thread is currently
+ waiting to join all threads, the number of non-daemon threads
+ is correct. */
- thread = threads_create_thread();
+ threads_mutex_join_lock();
- /* create a java.lang.Thread object */
+ /* create internal thread data-structure */
- t = (java_lang_Thread *) builtin_new(class_java_lang_Thread);
+ thread = threads_thread_new();
- if (t == NULL)
- return false;
+ /* thread is a Java thread and running */
- thread->object = t;
+ thread->flags = THREAD_FLAG_JAVA;
- /* thread is running */
+ if (isdaemon)
+ thread->flags |= THREAD_FLAG_DAEMON;
- thread->state = THREAD_STATE_RUNNABLE;
+ /* The thread is flagged and (non-)daemon thread, we can leave the
+ mutex. */
- /* insert the thread into the threadlist and the threads table */
+ threads_mutex_join_unlock();
- pthread_mutex_lock(&threadlistlock);
+ /* create a java.lang.Thread object */
- thread->prev = mainthreadobj;
- thread->next = mainthreadobj->next;
- mainthreadobj->next = thread;
- thread->next->prev = thread;
+ t = (java_lang_Thread *) builtin_new(class_java_lang_Thread);
- threads_table_add(thread);
+ /* XXX memory leak!!! */
+ if (t == NULL)
+ return false;
- pthread_mutex_unlock(&threadlistlock);
+ thread->object = t;
- /* mark thread as Java thread */
+ /* thread is completely initialized */
- thread->flags = THREAD_FLAG_JAVA;
+ threads_thread_state_runnable(thread);
- if (isdaemon)
- thread->flags |= THREAD_FLAG_DAEMON;
+#if !defined(NDEBUG)
+ if (opt_verbosethreads) {
+ printf("[Attaching thread ");
+ threads_thread_print_info(thread);
+ printf("]\n");
+ }
+#endif
#if defined(ENABLE_INTRP)
/* create interpreter stack */
#endif
#if defined(WITH_CLASSPATH_GNU)
+
/* create a java.lang.VMThread object */
vmt = (java_lang_VMThread *) builtin_new(class_java_lang_VMThread);
+ /* XXX memory leak!!! */
if (vmt == NULL)
return false;
/* set the thread */
- vmt->thread = t;
- vmt->vmdata = (java_lang_Object *) thread;
+ LLNI_field_set_ref(vmt, thread, t);
+ LLNI_field_set_val(vmt, vmdata, (java_lang_Object *) thread);
+
+#elif defined(WITH_CLASSPATH_SUN)
+
+ vm_abort("threads_attach_current_thread: IMPLEMENT ME!");
+
#elif defined(WITH_CLASSPATH_CLDC1_1)
- t->vm_thread = (java_lang_Object *) thread;
+
+ LLNI_field_set_val(t, vm_thread, (java_lang_Object *) thread);
+
+#else
+# error unknown classpath configuration
#endif
if (vm_aargs != NULL) {
else {
u = utf_null;
#if defined(ENABLE_JAVASE)
- group = mainthreadobj->object->group;
+ /* get the main thread */
+
+ mainthread = threads_list_first();
+ group = LLNI_field_direct(mainthread->object, group);
#endif
}
/* for convenience */
- o = (java_objectheader *) thread->object;
+ o = (java_handle_t *) thread->object;
#if defined(WITH_CLASSPATH_GNU)
(void) vm_call_method(method_thread_init, o, vmt, s, NORM_PRIORITY,
(void) vm_call_method(method_thread_init, o, s);
#endif
- if (*exceptionptr)
+ if (exceptions_get_exception())
return false;
#if defined(ENABLE_JAVASE)
/* store the thread group in the object */
- thread->object->group = group;
+ LLNI_field_direct(thread->object, group) = group;
/* add thread to given thread-group */
- m = class_resolveclassmethod(group->header.vftbl->class,
+ LLNI_class_get(group, c);
+
+ m = class_resolveclassmethod(c,
utf_addThread,
utf_java_lang_Thread__V,
class_java_lang_ThreadGroup,
true);
- o = (java_objectheader *) group;
+ o = (java_handle_t *) group;
(void) vm_call_method(m, o, t);
- if (*exceptionptr)
+ if (exceptions_get_exception())
return false;
#endif
*******************************************************************************/
-bool threads_detach_thread(threadobject *thread)
+bool threads_detach_thread(threadobject *t)
{
#if defined(ENABLE_JAVASE)
+ java_lang_Thread *object;
java_lang_ThreadGroup *group;
+ java_handle_t *e;
+ java_lang_Object *handler;
+ classinfo *c;
methodinfo *m;
- java_objectheader *o;
- java_lang_Thread *t;
+ java_handle_t *o;
#endif
- /* Allow lock record pools to be used by other threads. They
- cannot be deleted so we'd better not waste them. */
+#if defined(ENABLE_JAVASE)
+ object = t->object;
+
+ group = LLNI_field_direct(object, group);
- /* XXX We have to find a new way to free lock records */
- /* with the new locking algorithm. */
- /* lock_record_free_pools(thread->ee.lockrecordpools); */
+ /* If there's an uncaught exception, call uncaughtException on the
+ thread's exception handler, or the thread's group if this is
+ unset. */
- /* XXX implement uncaught exception stuff (like JamVM does) */
+ e = exceptions_get_and_clear_exception();
-#if defined(ENABLE_JAVASE)
- /* remove thread from the thread group */
+ if (e != NULL) {
+ /* We use a java_lang_Object here, as it's not trivial to
+ build the java_lang_Thread_UncaughtExceptionHandler header
+ file. */
+
+# if defined(WITH_CLASSPATH_GNU)
+ handler = (java_lang_Object *) LLNI_field_direct(object, exceptionHandler);
+# elif defined(WITH_CLASSPATH_SUN)
+ handler = (java_lang_Object *) LLNI_field_direct(object, uncaughtExceptionHandler);
+# endif
+
+ if (handler != NULL) {
+ LLNI_class_get(handler, c);
+ o = (java_handle_t *) handler;
+ }
+ else {
+ LLNI_class_get(group, c);
+ o = (java_handle_t *) group;
+ }
+
+ 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);
- group = thread->object->group;
+ if (exceptions_get_exception())
+ return false;
+ }
/* XXX TWISTI: should all threads be in a ThreadGroup? */
+ /* Remove thread from the thread group. */
+
if (group != NULL) {
- m = class_resolveclassmethod(group->header.vftbl->class,
+ LLNI_class_get(group, c);
+
+# if defined(WITH_CLASSPATH_GNU)
+ m = class_resolveclassmethod(c,
utf_removeThread,
utf_java_lang_Thread__V,
class_java_lang_ThreadGroup,
true);
+# elif defined(WITH_CLASSPATH_SUN)
+ m = class_resolveclassmethod(c,
+ utf_remove,
+ utf_java_lang_Thread__V,
+ class_java_lang_ThreadGroup,
+ true);
+# else
+# error unknown classpath configuration
+# endif
if (m == NULL)
return false;
- o = (java_objectheader *) group;
- t = thread->object;
+ o = (java_handle_t *) group;
- (void) vm_call_method(m, o, t);
+ (void) vm_call_method(m, o, object);
- if (*exceptionptr)
+ if (exceptions_get_exception())
return false;
}
#endif
/* thread is terminated */
- thread->state = THREAD_STATE_TERMINATED;
-
- /* lock thread list */
+ threads_thread_state_terminated(t);
- pthread_mutex_lock(&threadlistlock);
-
- /* remove thread from thread list and threads table */
+#if !defined(NDEBUG)
+ if (opt_verbosethreads) {
+ printf("[Detaching thread ");
+ threads_thread_print_info(t);
+ printf("]\n");
+ }
+#endif
- thread->next->prev = thread->prev;
- thread->prev->next = thread->next;
+ /* Enter the join-mutex before calling threads_thread_free, so
+ threads_join_all_threads gets the correct number of non-daemon
+ threads. */
- threads_table_remove(thread);
+ threads_mutex_join_lock();
- /* unlock thread list */
+ /* free the vm internal thread object */
- pthread_mutex_unlock(&threadlistlock);
+ threads_thread_free(t);
- /* signal that this thread has finished */
+ /* Signal that this thread has finished and leave the mutex. */
- pthread_mutex_lock(&mutex_join);
pthread_cond_signal(&cond_join);
- pthread_mutex_unlock(&mutex_join);
-
- /* free the vm internal thread object */
-
-#if defined(ENABLE_GC_BOEHM)
- GCFREE(thread);
-#else
- FREE(thread, threadobject);
-#endif
-
-#if defined(ENABLE_STATISTICS)
- if (opt_stat)
- size_threadobject -= sizeof(threadobject);
-#endif
+ threads_mutex_join_unlock();
return true;
}
-/* threads_find_non_daemon_thread **********************************************
-
- Helper function used by threads_join_all_threads for finding
- non-daemon threads that are still running.
-
-*******************************************************************************/
-
-static threadobject *threads_find_non_daemon_thread(void)
-{
- threadobject *thread;
-
- /* lock the thread list */
-
- pthread_mutex_lock(&threadlistlock);
-
- /* iterate over all threads */
-
- thread = mainthreadobj->next;
-
- while (thread != mainthreadobj) {
- if (!(thread->flags & THREAD_FLAG_DAEMON)) {
- /* unlock thread list */
-
- pthread_mutex_unlock(&threadlistlock);
-
- return thread;
- }
-
- thread = thread->next;
- }
-
- /* unlock thread list */
-
- pthread_mutex_unlock(&threadlistlock);
-
- return NULL;
-}
-
-
/* threads_join_all_threads ****************************************************
Join all non-daemon threads.
void threads_join_all_threads(void)
{
- threadobject *thread;
+ threadobject *t;
/* get current thread */
- thread = THREADOBJECT;
+ t = THREADOBJECT;
/* this thread is waiting for all non-daemon threads to exit */
- thread->state = THREAD_STATE_WAITING;
+ threads_thread_state_waiting(t);
/* enter join mutex */
- pthread_mutex_lock(&mutex_join);
+ threads_mutex_join_lock();
- /* wait for condition as long as we have non-daemon threads */
+ /* Wait for condition as long as we have non-daemon threads. We
+ compare against 1 because the current (main thread) is also a
+ non-daemon thread. */
- while (threads_find_non_daemon_thread() != NULL)
+ while (threads_list_get_non_daemons() > 1)
pthread_cond_wait(&cond_join, &mutex_join);
/* leave join mutex */
- pthread_mutex_unlock(&mutex_join);
+ threads_mutex_join_unlock();
}
while (!thread->interrupted && !thread->signaled
&& threads_current_time_is_earlier_than(wakeupTime))
{
- thread->state = THREAD_STATE_TIMED_WAITING;
+ threads_thread_state_timed_waiting(thread);
pthread_cond_timedwait(&thread->waitcond, &thread->waitmutex,
wakeupTime);
- thread->state = THREAD_STATE_RUNNABLE;
+ threads_thread_state_runnable(thread);
}
}
else {
/* no timeout */
while (!thread->interrupted && !thread->signaled) {
- thread->state = THREAD_STATE_WAITING;
+ threads_thread_state_waiting(thread);
pthread_cond_wait(&thread->waitcond, &thread->waitmutex);
- thread->state = THREAD_STATE_RUNNABLE;
+ threads_thread_state_runnable(thread);
}
}