Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.
- $Id: threads.c 7338 2007-02-13 00:17:22Z twisti $
+ $Id: threads.c 7809 2007-04-25 15:14:34Z twisti $
*/
#include "vmcore/options.h"
+#if defined(ENABLE_STATISTICS)
+# include "vmcore/statistics.h"
+#endif
+
#if !defined(__DARWIN__)
# if defined(__LINUX__)
# define GC_LINUX_THREADS
/* global threads table */
static threads_table_t threads_table;
-/* global compiler mutex */
-static pthread_mutex_t compiler_mutex;
-
/* global mutex for changing the thread list */
static pthread_mutex_t threadlistlock;
/* global mutex for stop-the-world */
static pthread_mutex_t stopworldlock;
+/* global mutex and condition for joining threads on exit */
+static pthread_mutex_t mutex_join;
+static pthread_cond_t cond_join;
+
/* this is one of the STOPWORLD_FROM_ constants, telling why the world is */
/* being stopped */
static volatile int stopworldwhere;
}
-/* compiler_lock ***************************************************************
-
- Enter the compiler lock.
-
-******************************************************************************/
-
-void compiler_lock(void)
-{
- pthread_mutex_lock(&compiler_mutex);
-}
-
-
-/* compiler_unlock *************************************************************
-
- Release the compiler lock.
-
-******************************************************************************/
-
-void compiler_unlock(void)
-{
- pthread_mutex_unlock(&compiler_mutex);
-}
-
-
/* lock_stopworld **************************************************************
Enter the stopworld lock, specifying why the world shall be stopped.
static void threads_init_threadobject(threadobject *thread)
{
+ /* get the pthread id */
+
thread->tid = pthread_self();
thread->index = 0;
/* TODO destroy all those things */
- pthread_mutex_init(&(thread->joinmutex), NULL);
- pthread_cond_init(&(thread->joincond), NULL);
pthread_mutex_init(&(thread->waitmutex), NULL);
pthread_cond_init(&(thread->waitcond), NULL);
thread->interrupted = false;
- thread->signaled = false;
- thread->sleeping = false;
+ thread->signaled = false;
+ thread->sleeping = false;
}
void threads_preinit(void)
{
- pthread_mutexattr_t mutexattr;
- pthread_mutexattr_init(&mutexattr);
- pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_RECURSIVE);
- pthread_mutex_init(&compiler_mutex, &mutexattr);
- pthread_mutexattr_destroy(&mutexattr);
-
pthread_mutex_init(&threadlistlock, NULL);
pthread_mutex_init(&stopworldlock, NULL);
+ /* initialize exit mutex and condition (on exit we join all
+ threads) */
+
+ pthread_mutex_init(&mutex_join, NULL);
+ pthread_cond_init(&cond_join, NULL);
+
+#if defined(ENABLE_GC_BOEHM)
+ mainthreadobj = GCNEW_UNCOLLECTABLE(threadobject, 1);
+#else
mainthreadobj = NEW(threadobject);
+#endif
+
+#if defined(ENABLE_STATISTICS)
+ if (opt_stat)
+ size_threadobject += sizeof(threadobject);
+#endif
+
+ mainthreadobj->object = NULL;
mainthreadobj->tid = pthread_self();
mainthreadobj->index = 1;
mainthreadobj->thinlock = lock_pre_compute_thinlock(mainthreadobj->index);
bool threads_init(void)
{
- java_lang_String *threadname;
- threadobject *tempthread;
+ java_objectheader *threadname;
+ java_lang_Thread *t;
java_objectheader *o;
#if defined(ENABLE_JAVASE)
java_lang_ThreadGroup *threadgroup;
methodinfo *m;
- java_lang_Thread *t;
#endif
#if defined(WITH_CLASSPATH_GNU)
java_lang_VMThread *vmt;
#endif
- tempthread = mainthreadobj;
-
- /* XXX We have to find a new way to free lock records */
- /* with the new locking algorithm. */
- /* lock_record_free_pools(mainthreadobj->ee.lockrecordpools); */
-
- /* This is kinda tricky, we grow the java.lang.Thread object so we
- can keep the execution environment there. No Thread object must
- have been created at an earlier time. */
-
- class_java_lang_Thread->instancesize = sizeof(threadobject);
-
/* get methods we need in this file */
#if defined(WITH_CLASSPATH_GNU)
/* create a java.lang.Thread for the main thread */
- mainthreadobj = (threadobject *) builtin_new(class_java_lang_Thread);
+ t = (java_lang_Thread *) builtin_new(class_java_lang_Thread);
- if (mainthreadobj == NULL)
+ if (t == NULL)
return false;
- FREE(tempthread, threadobject);
+ /* set the object in the internal data structure */
- threads_init_threadobject(mainthreadobj);
+ mainthreadobj->object = t;
+ threads_init_threadobject(mainthreadobj);
threads_set_current_threadobject(mainthreadobj);
-
lock_init_execution_env(mainthreadobj);
+ /* thread is running */
+
+ mainthreadobj->state = THREAD_STATE_RUNNABLE;
+
mainthreadobj->next = mainthreadobj;
mainthreadobj->prev = mainthreadobj;
native_new_and_init(class_java_lang_ThreadGroup);
if (threadgroup == NULL)
- throw_exception_exit();
+ return false;
#endif
#if defined(WITH_CLASSPATH_GNU)
vmt = (java_lang_VMThread *) builtin_new(class_java_lang_VMThread);
if (vmt == NULL)
- throw_exception_exit();
+ return false;
/* set the thread */
- t = (java_lang_Thread *) mainthreadobj;
vmt->thread = t;
+ vmt->vmdata = (java_lang_Object *) mainthreadobj;
/* call java.lang.Thread.<init>(Ljava/lang/VMThread;Ljava/lang/String;IZ)V */
- o = (java_objectheader *) mainthreadobj;
+ o = (java_objectheader *) t;
(void) vm_call_method(method_thread_init, o, vmt, threadname, NORM_PRIORITY,
false);
#elif defined(WITH_CLASSPATH_CLDC1_1)
+ /* set the thread */
+
+ t->vm_thread = (java_lang_Object *) mainthreadobj;
+
/* call public Thread(String name) */
- o = (java_objectheader *) mainthreadobj;
+ o = (java_objectheader *) t;
(void) vm_call_method(method_thread_init, o, threadname);
#endif
return false;
#if defined(ENABLE_JAVASE)
- mainthreadobj->o.group = threadgroup;
+ t->group = threadgroup;
/* add main thread to java.lang.ThreadGroup */
true);
o = (java_objectheader *) threadgroup;
- t = (java_lang_Thread *) mainthreadobj;
(void) vm_call_method(m, o, t);
if (*exceptionptr)
return false;
-
#endif
threads_set_thread_priority(pthread_self(), NORM_PRIORITY);
#endif
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 */
- threads_set_thread_priority(thread->tid, thread->o.priority);
+ threads_set_thread_priority(thread->tid, thread->object->priority);
#if defined(ENABLE_INTRP)
/* set interpreter stack */
c = class_java_lang_VMThread;
#elif defined(WITH_CLASSPATH_CLDC1_1)
- c = thread->o.header.vftbl->class;
+ c = thread->object->header.vftbl->class;
#endif
m = class_resolveclassmethod(c, utf_run, utf_void__void, c, true);
if (m == NULL)
- throw_exception();
+ vm_abort("threads_startup_thread: run() method not found in class");
/* set ThreadMXBean variables */
#if defined(WITH_CLASSPATH_GNU)
/* we need to start the run method of java.lang.VMThread */
- vmt = (java_lang_VMThread *) thread->o.vmThread;
+ vmt = (java_lang_VMThread *) thread->object->vmThread;
o = (java_objectheader *) vmt;
#elif defined(WITH_CLASSPATH_CLDC1_1)
- o = (java_objectheader *) thread;
+ o = (java_objectheader *) thread->object;
#endif
+ /* run the thread */
+
(void) vm_call_method(m, o);
}
else {
jvmti_ThreadStartEnd(JVMTI_EVENT_THREAD_END);
#endif
- threads_detach_thread(thread);
+ if (!threads_detach_thread(thread))
+ vm_abort("threads_startup_thread: threads_detach_thread failed");
/* set ThreadMXBean variables */
/* threads_start_thread ********************************************************
- Start a thread in the JVM.
+ Start a thread in the JVM. Both (vm internal and java) thread objects exist.
IN:
thread.......the thread object
struct sched_param schedp;
int policy;
-#if defined(ENABLE_JAVAME_CLDC1_1)
- /* The thread id is zero when a thread is created in Java. The
- priority is set later during startup. */
-
- if (tid == NULL)
- return;
-#endif
-
pthread_getschedparam(tid, &policy, &schedp);
schedp.sched_priority = priority;
pthread_setschedparam(tid, policy, &schedp);
{
threadobject *thread;
utf *u;
- java_lang_String *s;
+ java_objectheader *s;
java_objectheader *o;
java_lang_Thread *t;
java_lang_VMThread *vmt;
#endif
- /* create a java.lang.Thread object */
+ /* create a vm internal thread object */
- thread = (threadobject *) builtin_new(class_java_lang_Thread);
+#if defined(ENABLE_GC_BOEHM)
+ thread = GCNEW_UNCOLLECTABLE(threadobject, 1);
+#else
+ thread = NEW(threadobject);
+#endif
+
+#if defined(ENABLE_STATISTICS)
+ if (opt_stat)
+ size_threadobject += sizeof(threadobject);
+#endif
if (thread == NULL)
return false;
- /* cast for convenience */
+ /* create a java.lang.Thread object */
+
+ t = (java_lang_Thread *) builtin_new(class_java_lang_Thread);
- t = (java_lang_Thread *) thread;
+ if (t == NULL)
+ return false;
+
+ thread->object = t;
threads_init_threadobject(thread);
threads_set_current_threadobject(thread);
lock_init_execution_env(thread);
+ /* thread is running */
+
+ thread->state = THREAD_STATE_RUNNABLE;
+
/* insert the thread into the threadlist and the threads table */
pthread_mutex_lock(&threadlistlock);
/* set the thread */
vmt->thread = t;
+ vmt->vmdata = (java_lang_Object *) thread;
+#elif defined(WITH_CLASSPATH_CLDC1_1)
+ t->vm_thread = (java_lang_Object *) thread;
#endif
if (vm_aargs != NULL) {
else {
u = utf_null;
#if defined(ENABLE_JAVASE)
- group = mainthreadobj->o.group;
+ group = mainthreadobj->object->group;
#endif
}
+ /* the the thread name */
+
s = javastring_new(u);
- o = (java_objectheader *) thread;
+ /* for convenience */
+
+ o = (java_objectheader *) thread->object;
#if defined(WITH_CLASSPATH_GNU)
(void) vm_call_method(method_thread_init, o, vmt, s, NORM_PRIORITY,
#if defined(ENABLE_JAVASE)
/* store the thread group in the object */
- thread->o.group = group;
+ thread->object->group = group;
/* add thread to given thread-group */
#if defined(ENABLE_JAVASE)
/* remove thread from the thread group */
- group = thread->o.group;
+ group = thread->object->group;
/* XXX TWISTI: should all threads be in a ThreadGroup? */
return false;
o = (java_objectheader *) group;
- t = (java_lang_Thread *) thread;
+ t = thread->object;
(void) vm_call_method(m, o, t);
}
#endif
- /* remove thread from thread list and threads table, do this
- inside a lock */
+ /* thread is terminated */
+
+ thread->state = THREAD_STATE_TERMINATED;
+
+ /* lock thread list */
pthread_mutex_lock(&threadlistlock);
+ /* remove thread from thread list and threads table */
+
thread->next->prev = thread->prev;
thread->prev->next = thread->next;
threads_table_remove(thread);
+ /* unlock thread list */
+
pthread_mutex_unlock(&threadlistlock);
- /* reset thread id (lock on joinmutex? TWISTI) */
+ /* signal that this thread has finished */
- pthread_mutex_lock(&(thread->joinmutex));
- thread->tid = 0;
- pthread_mutex_unlock(&(thread->joinmutex));
+ pthread_mutex_lock(&mutex_join);
+ pthread_cond_signal(&cond_join);
+ pthread_mutex_unlock(&mutex_join);
- /* tell everyone that a thread has finished */
+ /* free the vm internal thread object */
- pthread_cond_broadcast(&(thread->joincond));
+#if defined(ENABLE_GC_BOEHM)
+ GCFREE(thread);
+#else
+ FREE(thread, threadobject);
+#endif
+
+#if defined(ENABLE_STATISTICS)
+ if (opt_stat)
+ size_threadobject -= sizeof(threadobject);
+#endif
return true;
}
*******************************************************************************/
-/* At the end of the program, we wait for all running non-daemon
- threads to die. */
-
-static threadobject *threads_find_non_daemon_thread(threadobject *thread)
+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))
+ if (!(thread->flags & THREAD_FLAG_DAEMON)) {
+ /* unlock thread list */
+
+ pthread_mutex_unlock(&threadlistlock);
+
return thread;
+ }
- thread = thread->prev;
+ thread = thread->next;
}
+ /* unlock thread list */
+
+ pthread_mutex_unlock(&threadlistlock);
+
return NULL;
}
{
threadobject *thread;
- pthread_mutex_lock(&threadlistlock);
+ /* get current thread */
- while ((thread = threads_find_non_daemon_thread(mainthreadobj->prev)) != NULL) {
- pthread_mutex_lock(&(thread->joinmutex));
+ thread = THREADOBJECT;
- pthread_mutex_unlock(&threadlistlock);
+ /* this thread is waiting for all non-daemon threads to exit */
- while (thread->tid)
- pthread_cond_wait(&(thread->joincond), &(thread->joinmutex));
+ thread->state = THREAD_STATE_WAITING;
- pthread_mutex_unlock(&(thread->joinmutex));
+ /* enter join mutex */
- pthread_mutex_lock(&threadlistlock);
- }
+ pthread_mutex_lock(&mutex_join);
- pthread_mutex_unlock(&threadlistlock);
+ /* wait for condition as long as we have non-daemon threads */
+
+ while (threads_find_non_daemon_thread() != NULL)
+ pthread_cond_wait(&cond_join, &mutex_join);
+
+ /* leave join mutex */
+
+ pthread_mutex_unlock(&mutex_join);
}
while (!thread->interrupted && !thread->signaled
&& threads_current_time_is_earlier_than(wakeupTime))
{
+ thread->state = THREAD_STATE_TIMED_WAITING;
+
pthread_cond_timedwait(&thread->waitcond, &thread->waitmutex,
wakeupTime);
+
+ thread->state = THREAD_STATE_RUNNABLE;
}
}
else {
/* no timeout */
- while (!thread->interrupted && !thread->signaled)
+ while (!thread->interrupted && !thread->signaled) {
+ thread->state = THREAD_STATE_WAITING;
+
pthread_cond_wait(&thread->waitcond, &thread->waitmutex);
+
+ thread->state = THREAD_STATE_RUNNABLE;
+ }
}
/* check if we were interrupted */
}
-/* threads_dump ****************************************************************
-
- Dumps info for all threads running in the JVM. This function is
- called when SIGQUIT (<ctrl>-\) is sent to CACAO.
-
-*******************************************************************************/
-
-void threads_dump(void)
-{
- threadobject *thread;
- java_lang_Thread *t;
- utf *name;
-
- thread = mainthreadobj;
-
- /* XXX we should stop the world here */
-
- printf("Full thread dump CACAO "VERSION":\n");
-
- /* iterate over all started threads */
-
- do {
- /* get thread object */
-
- t = (java_lang_Thread *) thread;
-
- /* the thread may be currently in initalization, don't print it */
-
- if (t != NULL) {
- /* get thread name */
-
-#if defined(ENABLE_JAVASE)
- name = javastring_toutf(t->name, false);
-#elif defined(ENABLE_JAVAME_CLDC1_1)
- name = t->name;
-#endif
-
- printf("\n\"");
- utf_display_printable_ascii(name);
- printf("\" ");
-
- if (thread->flags & THREAD_FLAG_DAEMON)
- printf("daemon ");
-
-#if SIZEOF_VOID_P == 8
- printf("prio=%d tid=0x%016lx\n", t->priority, (ptrint) thread->tid);
-#else
- printf("prio=%d tid=0x%08lx\n", t->priority, (ptrint) thread->tid);
-#endif
-
- /* dump trace of thread */
-
- stacktrace_dump_trace(thread);
- }
-
- thread = thread->next;
- } while ((thread != NULL) && (thread != mainthreadobj));
-}
-
-
/* threads_table_dump *********************************************************
Dump the threads table for debugging purposes.