/* src/threads/native/threads.c - native threads support
- Copyright (C) 1996-2005 R. Grafl, A. Krall, C. Kruegel, C. Oates,
- R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner,
- C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger,
- Institut f. Computersprachen - TU Wien
+ Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel,
+ C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
+ E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
+ J. Wenninger, Institut f. Computersprachen - TU Wien
This file is part of CACAO.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- 02111-1307, USA.
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
- Contact: cacao@complang.tuwien.ac.at
+ $Id: threads.c 7478 2007-03-08 02:59:31Z michi $
- Authors: Stefan Ring
-
- Changes: Christian Thalinger
+*/
- $Id: threads.c 4152 2006-01-12 21:14:03Z twisti $
-*/
+#include "config.h"
+/* XXX cleanup these includes */
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
-#include <semaphore.h>
-#include "config.h"
#include "vm/types.h"
-#ifndef USE_MD_THREAD_STUFF
-#include "machine-instr.h"
+#include "arch.h"
+
+#if !defined(USE_FAKE_ATOMIC_INSTRUCTIONS)
+# include "machine-instr.h"
#else
-#include "threads/native/generic-primitives.h"
+# include "threads/native/generic-primitives.h"
#endif
-#include "cacao/cacao.h"
-#include "mm/boehm.h"
+#include "mm/gc-common.h"
#include "mm/memory.h"
+
+#include "native/jni.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"
-#include "native/include/java_lang_ThreadGroup.h"
-#include "native/include/java_lang_VMThread.h"
+
+#if defined(ENABLE_JAVASE)
+# include "native/include/java_lang_ThreadGroup.h"
+#endif
+
+#if defined(WITH_CLASSPATH_GNU)
+# include "native/include/java_lang_VMThread.h"
+#endif
+
+#include "threads/threads-common.h"
+
#include "threads/native/threads.h"
+
#include "toolbox/avl.h"
#include "toolbox/logging.h"
+
#include "vm/builtin.h"
#include "vm/exceptions.h"
#include "vm/global.h"
-#include "vm/loader.h"
-#include "vm/options.h"
#include "vm/stringlocal.h"
+#include "vm/vm.h"
+
#include "vm/jit/asmpart.h"
+#include "vmcore/options.h"
+
#if !defined(__DARWIN__)
-#if defined(__LINUX__)
-#define GC_LINUX_THREADS
-#elif defined(__MIPS__)
-#define GC_IRIX_THREADS
-#endif
-#include "boehm-gc/include/gc.h"
+# if defined(__LINUX__)
+# define GC_LINUX_THREADS
+# elif defined(__MIPS__)
+# define GC_IRIX_THREADS
+# endif
+# include <semaphore.h>
+# if defined(ENABLE_GC_BOEHM)
+# include "mm/boehm-gc/include/gc.h"
+# endif
#endif
-#ifdef USE_MD_THREAD_STUFF
-pthread_mutex_t _atomic_add_lock = PTHREAD_MUTEX_INITIALIZER;
-pthread_mutex_t _cas_lock = PTHREAD_MUTEX_INITIALIZER;
-pthread_mutex_t _mb_lock = PTHREAD_MUTEX_INITIALIZER;
+#if defined(ENABLE_JVMTI)
+#include "native/jvmti/cacaodbg.h"
#endif
-#ifdef MUTEXSIM
+#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
+ 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.
+*/
+
+static int sem_init(sem_t *sem, int pshared, int value)
+{
+ if (pshared)
+ assert(0);
-/* We need this for older MacOSX (10.1.x) */
+ sem->value = value;
+
+ if (pthread_mutex_init(&sem->mutex, NULL) < 0)
+ return -1;
-typedef struct {
- pthread_mutex_t mutex;
- pthread_t owner;
- int count;
-} pthread_mutex_rec_t;
+ if (pthread_cond_init(&sem->cond, NULL) < 0)
+ return -1;
-static void pthread_mutex_init_rec(pthread_mutex_rec_t *m)
-{
- pthread_mutex_init(&m->mutex, NULL);
- m->count = 0;
+ return 0;
}
-static void pthread_mutex_destroy_rec(pthread_mutex_rec_t *m)
+static int sem_post(sem_t *sem)
{
- pthread_mutex_destroy(&m->mutex);
+ if (pthread_mutex_lock(&sem->mutex) < 0)
+ return -1;
+
+ sem->value++;
+
+ if (pthread_cond_signal(&sem->cond) < 0) {
+ pthread_mutex_unlock(&sem->mutex);
+ return -1;
+ }
+
+ if (pthread_mutex_unlock(&sem->mutex) < 0)
+ return -1;
+
+ return 0;
}
-static void pthread_mutex_lock_rec(pthread_mutex_rec_t *m)
+static int sem_wait(sem_t *sem)
{
- for (;;)
- if (!m->count)
- {
- pthread_mutex_lock(&m->mutex);
- m->owner = pthread_self();
- m->count++;
- break;
- } else {
- if (m->owner != pthread_self())
- pthread_mutex_lock(&m->mutex);
- else
- {
- m->count++;
- break;
- }
- }
+ if (pthread_mutex_lock(&sem->mutex) < 0)
+ return -1;
+
+ while (sem->value == 0) {
+ pthread_cond_wait(&sem->cond, &sem->mutex);
+ }
+
+ sem->value--;
+
+ if (pthread_mutex_unlock(&sem->mutex) < 0)
+ return -1;
+
+ return 0;
}
-static void pthread_mutex_unlock_rec(pthread_mutex_rec_t *m)
+static int sem_destroy(sem_t *sem)
{
- if (!--m->count)
- pthread_mutex_unlock(&m->mutex);
+ if (pthread_cond_destroy(&sem->cond) < 0)
+ return -1;
+
+ if (pthread_mutex_destroy(&sem->mutex) < 0)
+ return -1;
+
+ return 0;
}
+#endif /* defined(__DARWIN__) */
-#else /* MUTEXSIM */
-#define pthread_mutex_lock_rec pthread_mutex_lock
-#define pthread_mutex_unlock_rec pthread_mutex_unlock
-#define pthread_mutex_rec_t pthread_mutex_t
+/* internally used constants **************************************************/
-#endif /* MUTEXSIM */
+/* CAUTION: Do not change these values. Boehm GC code depends on them. */
+#define STOPWORLD_FROM_GC 1
+#define STOPWORLD_FROM_CLASS_NUMBERING 2
-static void setPriority(pthread_t tid, int priority)
-{
- struct sched_param schedp;
- int policy;
+#define THREADS_INITIAL_TABLE_SIZE 8
- pthread_getschedparam(tid, &policy, &schedp);
- schedp.sched_priority = priority;
- pthread_setschedparam(tid, policy, &schedp);
-}
+/* startupinfo *****************************************************************
+
+ Struct used to pass info from threads_start_thread to
+ threads_startup_thread.
-static avl_tree *criticaltree;
+******************************************************************************/
+
+typedef struct {
+ threadobject *thread; /* threadobject for this thread */
+ functionptr function; /* function to run in the new thread */
+ sem_t *psem; /* signals when thread has been entered */
+ /* in the thread list */
+ sem_t *psem_first; /* signals when pthread_create has returned */
+} startupinfo;
+
+
+/* prototypes *****************************************************************/
+
+static void threads_table_init(void);
+static s4 threads_table_add(threadobject *thread);
+static void threads_table_remove(threadobject *thread);
+static void threads_calc_absolute_time(struct timespec *tm, s8 millis, s4 nanos);
+
+#if !defined(NDEBUG) && 0
+static void threads_table_dump(FILE *file);
+#endif
+
+/******************************************************************************/
+/* GLOBAL VARIABLES */
+/******************************************************************************/
+
+/* the main thread */
threadobject *mainthreadobj;
-#ifndef HAVE___THREAD
-pthread_key_t tkey_threadinfo;
+static methodinfo *method_thread_init;
+
+/* the thread object of the current thread */
+/* This is either a thread-local variable defined with __thread, or */
+/* a thread-specific value stored with key threads_current_threadobject_key. */
+#if defined(HAVE___THREAD)
+__thread threadobject *threads_current_threadobject;
#else
-__thread threadobject *threadobj;
+pthread_key_t threads_current_threadobject_key;
#endif
-static pthread_mutex_rec_t compiler_mutex;
-static pthread_mutex_rec_t tablelock;
+/* global threads table */
+static threads_table_t threads_table;
-void compiler_lock()
-{
- pthread_mutex_lock_rec(&compiler_mutex);
-}
+/* global compiler mutex */
+static pthread_mutex_t compiler_mutex;
-void compiler_unlock()
-{
- pthread_mutex_unlock_rec(&compiler_mutex);
-}
+/* global mutex for changing the thread list */
+static pthread_mutex_t threadlistlock;
-void tables_lock()
-{
- pthread_mutex_lock_rec(&tablelock);
-}
+/* global mutex for stop-the-world */
+static pthread_mutex_t stopworldlock;
+
+/* this is one of the STOPWORLD_FROM_ constants, telling why the world is */
+/* being stopped */
+static volatile int stopworldwhere;
+
+/* semaphore used for acknowleding thread suspension */
+static sem_t suspend_ack;
+#if defined(__MIPS__)
+static pthread_mutex_t suspend_ack_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t suspend_cond = PTHREAD_COND_INITIALIZER;
+#endif
+
+static pthread_attr_t threadattr;
+
+/* mutexes used by the fake atomic instructions */
+#if defined(USE_FAKE_ATOMIC_INSTRUCTIONS)
+pthread_mutex_t _atomic_add_lock = PTHREAD_MUTEX_INITIALIZER;
+pthread_mutex_t _cas_lock = PTHREAD_MUTEX_INITIALIZER;
+pthread_mutex_t _mb_lock = PTHREAD_MUTEX_INITIALIZER;
+#endif
+
+
+/* threads_sem_init ************************************************************
+
+ Initialize a semaphore. Checks against errors and interruptions.
-void tables_unlock()
+ IN:
+ sem..............the semaphore to initialize
+ shared...........true if this semaphore will be shared between processes
+ value............the initial value for the semaphore
+
+*******************************************************************************/
+
+void threads_sem_init(sem_t *sem, bool shared, int value)
{
- pthread_mutex_unlock_rec(&tablelock);
+ int r;
+
+ assert(sem);
+
+ do {
+ r = sem_init(sem, shared, value);
+ if (r == 0)
+ return;
+ } while (errno == EINTR);
+
+ vm_abort("sem_init failed: %s", strerror(errno));
}
-static s4 criticalcompare(const void *pa, const void *pb)
+/* threads_sem_wait ************************************************************
+
+ Wait for a semaphore, non-interruptible.
+
+ IMPORTANT: Always use this function instead of `sem_wait` directly, as
+ `sem_wait` may be interrupted by signals!
+
+ IN:
+ sem..............the semaphore to wait on
+
+*******************************************************************************/
+
+void threads_sem_wait(sem_t *sem)
{
- const threadcritnode *na = pa;
- const threadcritnode *nb = pb;
+ int r;
- if (na->mcodebegin < nb->mcodebegin)
- return -1;
- if (na->mcodebegin > nb->mcodebegin)
- return 1;
- return 0;
+ assert(sem);
+
+ do {
+ r = sem_wait(sem);
+ if (r == 0)
+ return;
+ } while (errno == EINTR);
+
+ vm_abort("sem_wait failed: %s", strerror(errno));
}
-static const threadcritnode *findcritical(u1 *mcodeptr)
+/* threads_sem_post ************************************************************
+
+ Increase the count of a semaphore. Checks for errors.
+
+ IN:
+ sem..............the semaphore to increase the count of
+
+*******************************************************************************/
+
+void threads_sem_post(sem_t *sem)
{
- avl_node *n;
- const threadcritnode *m;
-
- n = criticaltree->root;
- m = NULL;
-
- if (!n)
- return NULL;
-
- for (;;) {
- const threadcritnode *d = n->data;
-
- if (mcodeptr == d->mcodebegin)
- return d;
-
- if (mcodeptr < d->mcodebegin) {
- if (n->childs[0])
- n = n->childs[0];
- else
- return m;
-
- } else {
- if (n->childs[1]) {
- m = n->data;
- n = n->childs[1];
- } else
- return n->data;
- }
- }
+ int r;
+
+ assert(sem);
+
+ /* unlike sem_wait, sem_post is not interruptible */
+
+ r = sem_post(sem);
+ if (r == 0)
+ return;
+
+ vm_abort("sem_post failed: %s", strerror(errno));
}
-void thread_registercritical(threadcritnode *n)
+/* compiler_lock ***************************************************************
+
+ Enter the compiler lock.
+
+******************************************************************************/
+
+void compiler_lock(void)
{
- avl_insert(criticaltree, n);
+ pthread_mutex_lock(&compiler_mutex);
}
-u1 *thread_checkcritical(u1 *mcodeptr)
+
+/* compiler_unlock *************************************************************
+
+ Release the compiler lock.
+
+******************************************************************************/
+
+void compiler_unlock(void)
{
- const threadcritnode *n = findcritical(mcodeptr);
- return (n && mcodeptr < n->mcodeend && mcodeptr > n->mcodebegin) ? n->mcoderestart : NULL;
+ pthread_mutex_unlock(&compiler_mutex);
}
-static void thread_addstaticcritical()
-{
- threadcritnode *n = &asm_criticalsections;
- while (n->mcodebegin)
- thread_registercritical(n++);
-}
+/* lock_stopworld **************************************************************
-static pthread_mutex_t threadlistlock;
+ Enter the stopworld lock, specifying why the world shall be stopped.
-static pthread_mutex_t stopworldlock;
-volatile int stopworldwhere;
+ IN:
+ where........ STOPWORLD_FROM_GC (1) from within GC
+ STOPWORLD_FROM_CLASS_NUMBERING (2) class numbering
-static sem_t suspend_ack;
-#if defined(__MIPS__)
-static pthread_mutex_t suspend_ack_lock = PTHREAD_MUTEX_INITIALIZER;
-static pthread_cond_t suspend_cond = PTHREAD_COND_INITIALIZER;
-#endif
+******************************************************************************/
-/*
- * where - 1 from within GC
- 2 class numbering
- */
void lock_stopworld(int where)
{
pthread_mutex_lock(&stopworldlock);
stopworldwhere = where;
}
-void unlock_stopworld()
+
+/* unlock_stopworld ************************************************************
+
+ Release the stopworld lock.
+
+******************************************************************************/
+
+void unlock_stopworld(void)
{
stopworldwhere = 0;
pthread_mutex_unlock(&stopworldlock);
#if !defined(__DARWIN__)
/* Caller must hold threadlistlock */
-static int cast_sendsignals(int sig, int count)
+static int threads_cast_sendsignals(int sig, int count)
{
/* Count threads */
threadobject *tobj = mainthreadobj;
- nativethread *infoself = THREADINFO;
+ threadobject *self = THREADOBJECT;
- if (count == 0)
+ if (count == 0) {
do {
count++;
- tobj = tobj->info.next;
+ tobj = tobj->next;
} while (tobj != mainthreadobj);
+ }
+
+ assert(tobj == mainthreadobj);
do {
- nativethread *info = &tobj->info;
- if (info != infoself)
- pthread_kill(info->tid, sig);
- tobj = tobj->info.next;
+ if (tobj != self)
+ pthread_kill(tobj->tid, sig);
+ tobj = tobj->next;
} while (tobj != mainthreadobj);
- return count-1;
+ return count - 1;
}
#else
-static void cast_darwinstop()
+static void threads_cast_darwinstop(void)
{
threadobject *tobj = mainthreadobj;
- nativethread *infoself = THREADINFO;
+ threadobject *self = THREADOBJECT;
do {
- nativethread *info = &tobj->info;
- if (info != infoself)
+ if (tobj != self)
{
- thread_state_flavor_t flavor = PPC_THREAD_STATE;
- mach_msg_type_number_t thread_state_count = PPC_THREAD_STATE_COUNT;
+ 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;
- mach_port_t thread = info->mach_thread;
+#endif
+ mach_port_t thread = tobj->mach_thread;
kern_return_t r;
r = thread_suspend(thread);
- if (r != KERN_SUCCESS) {
- log_text("thread_suspend failed");
- assert(0);
- }
-
- r = thread_get_state(thread, flavor,
- (natural_t*)&thread_state, &thread_state_count);
- if (r != KERN_SUCCESS) {
- log_text("thread_get_state failed");
- assert(0);
- }
-
- thread_restartcriticalsection(&thread_state);
-
- r = thread_set_state(thread, flavor,
- (natural_t*)&thread_state, thread_state_count);
- if (r != KERN_SUCCESS) {
- log_text("thread_set_state failed");
- assert(0);
- }
+
+ 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");
+
+ thread_restartcriticalsection((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->info.next;
+
+ tobj = tobj->next;
} while (tobj != mainthreadobj);
}
-static void cast_darwinresume()
+static void threads_cast_darwinresume(void)
{
threadobject *tobj = mainthreadobj;
- nativethread *infoself = THREADINFO;
+ threadobject *self = THREADOBJECT;
do {
- nativethread *info = &tobj->info;
- if (info != infoself)
+ if (tobj != self)
{
- mach_port_t thread = info->mach_thread;
+ mach_port_t thread = tobj->mach_thread;
kern_return_t r;
r = thread_resume(thread);
- if (r != KERN_SUCCESS) {
- log_text("thread_resume failed");
- assert(0);
- }
+
+ if (r != KERN_SUCCESS)
+ vm_abort("thread_resume failed");
}
- tobj = tobj->info.next;
+
+ tobj = tobj->next;
} while (tobj != mainthreadobj);
}
#endif
#if defined(__MIPS__)
-static void cast_irixresume()
+static void threads_cast_irixresume(void)
{
pthread_mutex_lock(&suspend_ack_lock);
pthread_cond_broadcast(&suspend_cond);
}
#endif
-void cast_stopworld()
+#if !defined(DISABLE_GC)
+
+void threads_cast_stopworld(void)
{
+#if !defined(__DARWIN__) && !defined(__CYGWIN__)
int count, i;
- lock_stopworld(2);
+#endif
+
+ lock_stopworld(STOPWORLD_FROM_CLASS_NUMBERING);
pthread_mutex_lock(&threadlistlock);
+
#if defined(__DARWIN__)
- cast_darwinstop();
+ threads_cast_darwinstop();
+#elif defined(__CYGWIN__)
+ /* TODO */
+ assert(0);
#else
- count = cast_sendsignals(GC_signum1(), 0);
- for (i=0; i<count; i++)
- sem_wait(&suspend_ack);
+ count = threads_cast_sendsignals(GC_signum1(), 0);
+ for (i = 0; i < count; i++)
+ threads_sem_wait(&suspend_ack);
#endif
+
pthread_mutex_unlock(&threadlistlock);
}
-void cast_startworld()
+void threads_cast_startworld(void)
{
pthread_mutex_lock(&threadlistlock);
#if defined(__DARWIN__)
- cast_darwinresume();
+ threads_cast_darwinresume();
#elif defined(__MIPS__)
- cast_irixresume();
+ threads_cast_irixresume();
+#elif defined(__CYGWIN__)
+ /* TODO */
+ assert(0);
#else
- cast_sendsignals(GC_signum2(), -1);
+ threads_cast_sendsignals(GC_signum2(), -1);
#endif
pthread_mutex_unlock(&threadlistlock);
unlock_stopworld();
}
+
#if !defined(__DARWIN__)
-static void sigsuspend_handler(ucontext_t *ctx)
+static void threads_sigsuspend_handler(ucontext_t *ctx)
{
int sig;
sigset_t sigs;
-
+
+ /* XXX TWISTI: this is just a quick hack */
+#if defined(ENABLE_JIT)
thread_restartcriticalsection(ctx);
+#endif
/* Do as Boehm does. On IRIX a condition variable is used for wake-up
(not POSIX async-safe). */
#if defined(__IRIX__)
pthread_mutex_lock(&suspend_ack_lock);
- sem_post(&suspend_ack);
+ threads_sem_post(&suspend_ack);
pthread_cond_wait(&suspend_cond, &suspend_ack_lock);
pthread_mutex_unlock(&suspend_ack_lock);
+#elif defined(__CYGWIN__)
+ /* TODO */
+ assert(0);
#else
- sem_post(&suspend_ack);
+ threads_sem_post(&suspend_ack);
sig = GC_signum2();
sigfillset(&sigs);
#endif
}
+/* This function is called from Boehm GC code. */
+
int cacao_suspendhandler(ucontext_t *ctx)
{
- if (stopworldwhere != 2)
+ if (stopworldwhere != STOPWORLD_FROM_CLASS_NUMBERING)
return 0;
- sigsuspend_handler(ctx);
+ threads_sigsuspend_handler(ctx);
return 1;
}
#endif
-static void setthreadobject(threadobject *thread)
+#endif /* DISABLE_GC */
+
+/* threads_set_current_threadobject ********************************************
+
+ Set the current thread object.
+
+ IN:
+ thread.......the thread object to set
+
+*******************************************************************************/
+
+static void threads_set_current_threadobject(threadobject *thread)
{
#if !defined(HAVE___THREAD)
- pthread_setspecific(tkey_threadinfo, thread);
+ pthread_setspecific(threads_current_threadobject_key, thread);
#else
- threadobj = thread;
+ threads_current_threadobject = thread;
#endif
}
-/* thread_setself **************************************************************
+/* threads_init_threadobject **************************************************
- XXX
+ Initialize implementation fields of a threadobject.
-*******************************************************************************/
+ IN:
+ thread............the threadobject
-void *thread_getself(void)
+******************************************************************************/
+
+static void threads_init_threadobject(threadobject *thread)
{
- return pthread_getspecific(tkey_threadinfo);
+ 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;
}
-static monitorLockRecord *dummyLR;
+/* threads_get_current_threadobject ********************************************
+
+ Return the threadobject of the current thread.
+
+ RETURN VALUE:
+ the current threadobject * (an instance of java.lang.Thread)
+
+*******************************************************************************/
-static void initPools();
+threadobject *threads_get_current_threadobject(void)
+{
+ return THREADOBJECT;
+}
-/* thread_preinit **************************************************************
+/* threads_preinit *************************************************************
Do some early initialization of stuff required.
+ ATTENTION: Do NOT use any Java heap allocation here, as gc_init()
+ is called AFTER this function!
+
*******************************************************************************/
void threads_preinit(void)
{
-#ifndef MUTEXSIM
pthread_mutexattr_t mutexattr;
pthread_mutexattr_init(&mutexattr);
pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&compiler_mutex, &mutexattr);
- pthread_mutex_init(&tablelock, &mutexattr);
pthread_mutexattr_destroy(&mutexattr);
-#else
- pthread_mutex_init_rec(&compiler_mutex);
- pthread_mutex_init_rec(&tablelock);
-#endif
pthread_mutex_init(&threadlistlock, NULL);
pthread_mutex_init(&stopworldlock, NULL);
- /* Allocate something so the garbage collector's signal handlers
- are installed. */
- heap_allocate(1, false, NULL);
-
mainthreadobj = NEW(threadobject);
- mainthreadobj->info.tid = pthread_self();
+ mainthreadobj->object = NULL;
+ mainthreadobj->tid = pthread_self();
+ mainthreadobj->index = 1;
+ mainthreadobj->thinlock = lock_pre_compute_thinlock(mainthreadobj->index);
+
#if !defined(HAVE___THREAD)
- pthread_key_create(&tkey_threadinfo, NULL);
+ pthread_key_create(&threads_current_threadobject_key, NULL);
#endif
- setthreadobject(mainthreadobj);
- initPools();
-
- /* Every newly created object's monitorPtr points here so we save
- a check against NULL */
+ threads_set_current_threadobject(mainthreadobj);
- dummyLR = NEW(monitorLockRecord);
- dummyLR->o = NULL;
- dummyLR->ownerThread = NULL;
- dummyLR->waiting = false;
+ threads_sem_init(&suspend_ack, 0, 0);
- /* we need a working dummyLR before initializing the critical
- section tree */
+ /* initialize the threads table */
- criticaltree = avl_create(&criticalcompare);
-
- thread_addstaticcritical();
- sem_init(&suspend_ack, 0, 0);
-}
+ threads_table_init();
+ /* initialize subsystems */
-static pthread_attr_t threadattr;
+ lock_init();
-static void freeLockRecordPools(lockRecordPool *);
+ critical_init();
+}
/* threads_init ****************************************************************
*******************************************************************************/
-bool threads_init(u1 *stackbottom)
+bool threads_init(void)
{
java_lang_String *threadname;
- java_lang_Thread *mainthread;
- java_lang_ThreadGroup *threadgroup;
threadobject *tempthread;
- methodinfo *method;
+ 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;
- freeLockRecordPools(mainthreadobj->ee.lrpool);
+ /* XXX We have to find a new way to free lock records */
+ /* with the new locking algorithm. */
+ /* lock_record_free_pools(mainthreadobj->ee.lockrecordpools); */
+#if 0
/* 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_VMThread->instancesize = sizeof(threadobject);
+ class_java_lang_Thread->instancesize = sizeof(threadobject);
+#endif
+
+ /* get methods we need in this file */
- /* create a VMThread */
+#if defined(WITH_CLASSPATH_GNU)
+ method_thread_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);
+#else
+ method_thread_init =
+ class_resolveclassmethod(class_java_lang_Thread,
+ utf_init,
+ utf_new_char("(Ljava/lang/String;)V"),
+ class_java_lang_Thread,
+ true);
+#endif
+
+ if (method_thread_init == NULL)
+ return false;
+
+ /* create a vm internal thread object for the main thread */
+ /* XXX Michi: we do not need to do this here, we could use the one
+ created by threads_preinit() */
+
+#if defined(ENABLE_GC_CACAO)
+ mainthreadobj = NEW(threadobject);
+#else
+ mainthreadobj = GCNEW(threadobject);
+#endif
+
+ if (mainthreadobj == NULL)
+ return false;
+
+ /* create a java.lang.Thread for the main thread */
- mainthreadobj = (threadobject *) builtin_new(class_java_lang_VMThread);
+ mainthreadobj->object = (java_lang_Thread *) builtin_new(class_java_lang_Thread);
- if (!mainthreadobj)
+ if (mainthreadobj->object == NULL)
return false;
FREE(tempthread, threadobject);
- initThread(&mainthreadobj->o);
+ threads_init_threadobject(mainthreadobj);
- setthreadobject(mainthreadobj);
+ threads_set_current_threadobject(mainthreadobj);
- initLocks();
+ lock_init_execution_env(mainthreadobj);
- mainthreadobj->info.next = mainthreadobj;
- mainthreadobj->info.prev = mainthreadobj;
+ mainthreadobj->next = mainthreadobj;
+ mainthreadobj->prev = mainthreadobj;
+
+ threads_table_add(mainthreadobj);
+
+ /* mark main thread as Java thread */
+
+ mainthreadobj->flags = THREAD_FLAG_JAVA;
#if defined(ENABLE_INTRP)
/* create interpreter stack */
if (opt_intrp) {
MSET(intrp_main_stack, 0, u1, opt_stacksize);
- mainthreadobj->info._global_sp = intrp_main_stack + opt_stacksize;
+ mainthreadobj->_global_sp = (Cell*) (intrp_main_stack + opt_stacksize);
}
#endif
threadname = javastring_new(utf_new_char("main"));
+#if defined(ENABLE_JAVASE)
/* allocate and init ThreadGroup */
threadgroup = (java_lang_ThreadGroup *)
native_new_and_init(class_java_lang_ThreadGroup);
- if (!threadgroup)
+ if (threadgroup == NULL)
throw_exception_exit();
+#endif
- /* create a Thread */
+#if defined(WITH_CLASSPATH_GNU)
+ /* create a java.lang.VMThread for the main thread */
- mainthread = (java_lang_Thread *) builtin_new(class_java_lang_Thread);
+ vmt = (java_lang_VMThread *) builtin_new(class_java_lang_VMThread);
- if (!mainthread)
+ if (vmt == NULL)
throw_exception_exit();
- mainthreadobj->o.thread = mainthread;
+ /* set the thread */
- /* call Thread.<init>(Ljava/lang/VMThread;Ljava/lang/String;IZ)V */
+ vmt->thread = mainthreadobj->object;
+ vmt->vmdata = (java_lang_Object *) mainthreadobj;
- method = class_resolveclassmethod(class_java_lang_Thread,
- utf_init,
- utf_new_char("(Ljava/lang/VMThread;Ljava/lang/String;IZ)V"),
- class_java_lang_Thread,
- true);
+ /* call java.lang.Thread.<init>(Ljava/lang/VMThread;Ljava/lang/String;IZ)V */
+ o = (java_objectheader *) mainthreadobj->object;
- if (!method)
- return false;
+ (void) vm_call_method(method_thread_init, o, vmt, threadname, NORM_PRIORITY,
+ false);
+#elif defined(WITH_CLASSPATH_CLDC1_1)
+ /* set the thread */
+
+ mainthreadobj->object->vm_thread = (java_lang_Object *) mainthreadobj;
+
+ /* call public Thread(String name) */
+
+ o = (java_objectheader *) mainthreadobj->object;
- ASM_CALLJAVAFUNCTION(method, mainthread, mainthreadobj, threadname,
- (void *) 5);
+ (void) vm_call_method(method_thread_init, o, threadname);
+#endif
if (*exceptionptr)
return false;
- mainthread->group = threadgroup;
- /* XXX This is a hack because the fourth argument was omitted */
- mainthread->daemon = false;
+#if defined(ENABLE_JAVASE)
+ mainthreadobj->object->group = threadgroup;
- /* add mainthread to ThreadGroup */
+ /* add main thread to java.lang.ThreadGroup */
- method = class_resolveclassmethod(class_java_lang_ThreadGroup,
- utf_new_char("addThread"),
- utf_new_char("(Ljava/lang/Thread;)V"),
- class_java_lang_ThreadGroup,
- true);
+ m = class_resolveclassmethod(class_java_lang_ThreadGroup,
+ utf_addThread,
+ utf_java_lang_Thread__V,
+ class_java_lang_ThreadGroup,
+ true);
- if (!method)
- return false;
+ o = (java_objectheader *) threadgroup;
+ t = mainthreadobj->object;
- ASM_CALLJAVAFUNCTION(method, threadgroup, mainthread, NULL, NULL);
+ (void) vm_call_method(m, o, t);
if (*exceptionptr)
return false;
- setPriority(pthread_self(), 5);
+#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;
+ }
- pthread_attr_init(&threadattr);
pthread_attr_setdetachstate(&threadattr, PTHREAD_CREATE_DETACHED);
/* everything's ok */
}
-void initThread(java_lang_VMThread *t)
+/* threads_table_init *********************************************************
+
+ Initialize the global threads table.
+
+******************************************************************************/
+
+static void threads_table_init(void)
{
- threadobject *thread = (threadobject*) t;
- nativethread *info = &thread->info;
- info->tid = pthread_self();
- /* TODO destroy all those things */
- pthread_mutex_init(&info->joinMutex, NULL);
- pthread_cond_init(&info->joinCond, NULL);
+ s4 size;
+ s4 i;
- pthread_mutex_init(&thread->waitLock, NULL);
- pthread_cond_init(&thread->waitCond, NULL);
- thread->interrupted = false;
- thread->signaled = false;
- thread->isSleeping = false;
+ size = THREADS_INITIAL_TABLE_SIZE;
+
+ threads_table.size = size;
+ threads_table.table = MNEW(threads_table_entry_t, size);
+
+ /* link the entries in a freelist */
+
+ for (i=0; i<size; ++i) {
+ threads_table.table[i].nextfree = i+1;
+ }
+
+ /* terminate the freelist */
+
+ threads_table.table[size-1].nextfree = 0; /* index 0 is never free */
}
-static void initThreadLocks(threadobject *);
+/* threads_table_add **********************************************************
-typedef struct {
- threadobject *thread;
- functionptr function;
- sem_t *psem;
- sem_t *psem_first;
-} startupinfo;
+ Add a thread to the global threads table. The index is entered in the
+ threadobject. The thinlock value for the thread is pre-computed.
+ IN:
+ thread............the thread to add
-/* threads_startup *************************************************************
+ RETURN VALUE:
+ The table index for the newly added thread. This value has also been
+ entered in the threadobject.
- Thread startup function called by pthread_create.
+ PRE-CONDITION:
+ The caller must hold the threadlistlock!
******************************************************************************/
-static void *threads_startup_thread(void *t)
+static s4 threads_table_add(threadobject *thread)
{
- startupinfo *startup;
- threadobject *thread;
- sem_t *psem;
- nativethread *info;
- threadobject *tnext;
- methodinfo *method;
- functionptr function;
+ s4 index;
+ s4 oldsize;
+ s4 newsize;
+ s4 i;
-#if defined(ENABLE_INTRP)
+ /* table[0] serves as the head of the freelist */
+
+ index = threads_table.table[0].nextfree;
+
+ /* if we got a free index, use it */
+
+ if (index) {
+got_an_index:
+ threads_table.table[0].nextfree = threads_table.table[index].nextfree;
+ threads_table.table[index].thread = thread;
+ thread->index = index;
+ thread->thinlock = lock_pre_compute_thinlock(index);
+ return index;
+ }
+
+ /* we must grow the table */
+
+ oldsize = threads_table.size;
+ newsize = oldsize * 2;
+
+ threads_table.table = MREALLOC(threads_table.table, threads_table_entry_t,
+ oldsize, newsize);
+ threads_table.size = newsize;
+
+ /* link the new entries to a free list */
+
+ for (i=oldsize; i<newsize; ++i) {
+ threads_table.table[i].nextfree = i+1;
+ }
+
+ /* terminate the freelist */
+
+ threads_table.table[newsize-1].nextfree = 0; /* index 0 is never free */
+
+ /* use the first of the new entries */
+
+ index = oldsize;
+ goto got_an_index;
+}
+
+
+/* threads_table_remove *******************************************************
+
+ Remove a thread from the global threads table.
+
+ IN:
+ thread............the thread to remove
+
+ PRE-CONDITION:
+ The caller must hold the threadlistlock!
+
+******************************************************************************/
+
+static void threads_table_remove(threadobject *thread)
+{
+ s4 index;
+
+ index = thread->index;
+
+ /* put the index into the freelist */
+
+ threads_table.table[index] = threads_table.table[0];
+ threads_table.table[0].nextfree = index;
+
+ /* delete the index in the threadobject to discover bugs */
+#if !defined(NDEBUG)
+ thread->index = 0;
+#endif
+}
+
+
+/* threads_startup_thread ******************************************************
+
+ Thread startup function called by pthread_create.
+
+ Thread which have a startup.function != NULL are marked as internal
+ threads. All other threads are threated as normal Java threads.
+
+ NOTE: This function is not called directly by pthread_create. The Boehm GC
+ inserts its own GC_start_routine in between, which then calls
+ threads_startup.
+
+ IN:
+ t............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)
+{
+ startupinfo *startup;
+ threadobject *thread;
+#if defined(WITH_CLASSPATH_GNU)
+ java_lang_VMThread *vmt;
+#endif
+ sem_t *psem;
+ threadobject *tnext;
+ classinfo *c;
+ methodinfo *m;
+ java_objectheader *o;
+ functionptr function;
+
+#if defined(ENABLE_INTRP)
u1 *intrp_thread_stack;
/* create interpreter stack */
if (opt_intrp) {
- intrp_thread_stack = (u1 *) alloca(opt_stacksize);
+ intrp_thread_stack = GCMNEW(u1, opt_stacksize);
MSET(intrp_thread_stack, 0, u1, opt_stacksize);
}
+ else
+ intrp_thread_stack = NULL;
#endif
/* get passed startupinfo structure and the values in there */
startup = t;
+ t = NULL; /* make sure it's not used wrongly */
thread = startup->thread;
function = startup->function;
psem = startup->psem;
- info = &thread->info;
-
- /* Seems like we've encountered a situation where info->tid was not set by
+ /* 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. */
- sem_wait(startup->psem_first);
+ threads_sem_wait(startup->psem_first);
+
+ /* set the thread object */
- t = NULL;
#if defined(__DARWIN__)
- info->mach_thread = mach_thread_self();
+ thread->mach_thread = mach_thread_self();
#endif
- setthreadobject(thread);
+ threads_set_current_threadobject(thread);
- /* insert the thread into the threadlist */
+ /* insert the thread into the threadlist and the threads table */
pthread_mutex_lock(&threadlistlock);
- info->prev = mainthreadobj;
- info->next = tnext = mainthreadobj->info.next;
- mainthreadobj->info.next = thread;
- tnext->info.prev = thread;
+ thread->prev = mainthreadobj;
+ thread->next = tnext = mainthreadobj->next;
+ mainthreadobj->next = thread;
+ tnext->prev = thread;
+
+ threads_table_add(thread);
pthread_mutex_unlock(&threadlistlock);
- initThreadLocks(thread);
+ /* init data structures of this thread */
+
+ lock_init_execution_env(thread);
+
+ /* tell threads_startup_thread that we registered ourselves */
+ /* CAUTION: *startup becomes invalid with this! */
startup = NULL;
- sem_post(psem);
+ threads_sem_post(psem);
+
+ /* set our priority */
- setPriority(info->tid, thread->o.thread->priority);
+ threads_set_thread_priority(thread->tid, thread->object->priority);
#if defined(ENABLE_INTRP)
/* set interpreter stack */
if (opt_intrp)
- THREADINFO->_global_sp = (void *) (intrp_thread_stack + opt_stacksize);
+ 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
/* find and run the Thread.run()V method if no other function was passed */
if (function == NULL) {
- method = class_resolveclassmethod(thread->o.header.vftbl->class,
- utf_run,
- utf_void__void,
- thread->o.header.vftbl->class,
- true);
+ /* 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. */
- if (!method)
+ c = class_java_lang_VMThread;
+#elif defined(WITH_CLASSPATH_CLDC1_1)
+ c = thread->object->header.vftbl->class;
+#endif
+
+ m = class_resolveclassmethod(c, utf_run, utf_void__void, c, true);
+
+ if (m == NULL)
throw_exception();
- ASM_CALLJAVAFUNCTION(method, thread, NULL, NULL, NULL);
+ /* 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;
+
+#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;
+
+#elif defined(WITH_CLASSPATH_CLDC1_1)
+ o = (java_objectheader *) thread->object;
+#endif
+
+ (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++;
+ _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;
- } else {
/* call passed function, e.g. finalizer_thread */
(function)();
}
- /* Allow lock record pools to be used by other threads. They
- cannot be deleted so we'd better not waste them. */
+#if defined(ENABLE_JVMTI)
+ /* fire thread end event */
- freeLockRecordPools(thread->ee.lrpool);
+ if (jvmti)
+ jvmti_ThreadStartEnd(JVMTI_EVENT_THREAD_END);
+#endif
- /* remove thread from thread list, do this inside a lock */
+ threads_detach_thread(thread);
- pthread_mutex_lock(&threadlistlock);
- info->next->info.prev = info->prev;
- info->prev->info.next = info->next;
- pthread_mutex_unlock(&threadlistlock);
+ /* set ThreadMXBean variables */
- /* reset thread id (lock on joinMutex? TWISTI) */
+ _Jv_jvm->java_lang_management_ThreadMXBean_ThreadCount--;
- pthread_mutex_lock(&info->joinMutex);
- info->tid = 0;
- pthread_mutex_unlock(&info->joinMutex);
+ return NULL;
+}
- pthread_cond_broadcast(&info->joinCond);
- return NULL;
+/* threads_start_javathread ***************************************************
+
+ Start a thread in the JVM. Only the java thread object exists so far.
+
+ IN:
+ object.....the java thread object java.lang.Thread
+
+******************************************************************************/
+
+void threads_start_javathread(java_lang_Thread *object)
+{
+ threadobject *thread;
+
+ /* create the vm internal threadobject */
+
+ thread = NEW(threadobject);
+ assert(thread);
+
+ /* link the two objects together */
+
+ thread->object = object;
+
+#if defined(WITH_CLASSPATH_GNU)
+ assert(object->vmThread);
+ assert(object->vmThread->vmdata == NULL);
+ object->vmThread->vmdata = (java_lang_Object *) thread;
+#elif defined(WITH_CLASSPATH_CLDC1_1)
+ object->vm_thread = (java_lang_Object *) thread;
+#endif
+
+ /* actually start the thread */
+ /* don't pass a function pointer (NULL) since we want Thread.run()V here */
+
+ threads_start_thread(thread, NULL);
}
/* 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
+ function.....function to run in the new thread. NULL means that the
+ "run" method of the object `t` should be called
******************************************************************************/
-void threads_start_thread(thread *t, functionptr function)
+void threads_start_thread(threadobject *thread, functionptr function)
{
- nativethread *info;
- sem_t sem;
- sem_t sem_first;
- startupinfo startup;
-
- info = &((threadobject *) t->vmThread)->info;
+ sem_t sem;
+ sem_t sem_first;
+ pthread_attr_t attr;
+ startupinfo startup;
- /* fill startupinfo structure passed by pthread_create to XXX */
+ /* fill startupinfo structure passed by pthread_create to
+ * threads_startup_thread */
- startup.thread = (threadobject*) t->vmThread;
+ startup.thread = thread;
startup.function = function; /* maybe we don't call Thread.run()V */
startup.psem = &sem;
startup.psem_first = &sem_first;
- sem_init(&sem, 0, 0);
- sem_init(&sem_first, 0, 0);
-
- if (pthread_create(&info->tid, &threadattr, threads_startup_thread,
- &startup)) {
- log_text("pthread_create failed");
- assert(0);
- }
+ threads_sem_init(&sem, 0, 0);
+ threads_sem_init(&sem_first, 0, 0);
+
+ /* initialize thread attribute object */
- sem_post(&sem_first);
+ if (pthread_attr_init(&attr))
+ vm_abort("pthread_attr_init failed: %s", strerror(errno));
+
+ /* initialize thread stacksize */
+
+ if (pthread_attr_setstacksize(&attr, opt_stacksize))
+ vm_abort("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));
+
+ /* signal that pthread_create has returned, so thread->tid is valid */
+
+ threads_sem_post(&sem_first);
/* wait here until the thread has entered itself into the thread list */
- sem_wait(&sem);
+ threads_sem_wait(&sem);
+
+ /* cleanup */
+
sem_destroy(&sem);
sem_destroy(&sem_first);
}
-/* At the end of the program, we wait for all running non-daemon threads to die
- */
+/* threads_set_thread_priority *************************************************
+
+ Set the priority of the given thread.
+
+ IN:
+ tid..........thread id
+ priority.....priority to set
+
+******************************************************************************/
-static threadobject *findNonDaemon(threadobject *thread)
+void threads_set_thread_priority(pthread_t tid, int priority)
{
- while (thread != mainthreadobj) {
- if (!thread->o.thread->daemon)
- return thread;
- thread = thread->info.prev;
- }
+ struct sched_param schedp;
+ int policy;
- return NULL;
+ pthread_getschedparam(tid, &policy, &schedp);
+ schedp.sched_priority = priority;
+ pthread_setschedparam(tid, policy, &schedp);
}
-void joinAllThreads()
+
+/* threads_attach_current_thread ***********************************************
+
+ Attaches the current thread to the VM. Used in JNI.
+
+*******************************************************************************/
+
+bool threads_attach_current_thread(JavaVMAttachArgs *vm_aargs, bool isdaemon)
{
- threadobject *thread;
+ threadobject *thread;
+ utf *u;
+ java_lang_String *s;
+ java_objectheader *o;
+ java_lang_Thread *t;
+
+#if defined(ENABLE_JAVASE)
+ java_lang_ThreadGroup *group;
+ methodinfo *m;
+#endif
+
+#if defined(WITH_CLASSPATH_GNU)
+ java_lang_VMThread *vmt;
+#endif
+
+ /* create a vm internal thread object */
+
+ thread = NEW(threadobject);
+
+ if (thread == NULL)
+ return false;
+
+ /* create a java.lang.Thread object */
+
+ t = (java_lang_Thread *) builtin_new(class_java_lang_Thread);
+
+ if (t == NULL)
+ return false;
+
+ thread->object = t;
+
+ threads_init_threadobject(thread);
+ threads_set_current_threadobject(thread);
+ lock_init_execution_env(thread);
+
+ /* insert the thread into the threadlist and the threads table */
+
pthread_mutex_lock(&threadlistlock);
- while ((thread = findNonDaemon(mainthreadobj->info.prev)) != NULL) {
- nativethread *info = &thread->info;
- pthread_mutex_lock(&info->joinMutex);
- pthread_mutex_unlock(&threadlistlock);
- while (info->tid)
- pthread_cond_wait(&info->joinCond, &info->joinMutex);
- pthread_mutex_unlock(&info->joinMutex);
- pthread_mutex_lock(&threadlistlock);
- }
- pthread_mutex_unlock(&threadlistlock);
-}
-static void initLockRecord(monitorLockRecord *r, threadobject *t)
-{
- r->lockCount = 1;
- r->ownerThread = t;
- r->queuers = 0;
- r->o = NULL;
- r->waiter = NULL;
- r->incharge = (monitorLockRecord *) &dummyLR;
- r->waiting = false;
- sem_init(&r->queueSem, 0, 0);
- pthread_mutex_init(&r->resolveLock, NULL);
- pthread_cond_init(&r->resolveWait, NULL);
-}
+ thread->prev = mainthreadobj;
+ thread->next = mainthreadobj->next;
+ mainthreadobj->next = thread;
+ thread->next->prev = thread;
-/* No lock record must ever be destroyed because there may still be references
- * to it.
+ threads_table_add(thread);
-static void destroyLockRecord(monitorLockRecord *r)
-{
- sem_destroy(&r->queueSem);
- pthread_mutex_destroy(&r->resolveLock);
- pthread_cond_destroy(&r->resolveWait);
-}
-*/
+ pthread_mutex_unlock(&threadlistlock);
-void initLocks()
-{
- initThreadLocks(mainthreadobj);
-}
+ /* mark thread as Java thread */
-static void initThreadLocks(threadobject *thread)
-{
- thread->ee.firstLR = NULL;
- thread->ee.lrpool = NULL;
- thread->ee.numlr = 0;
-}
+ thread->flags = THREAD_FLAG_JAVA;
-static lockRecordPool *allocNewLockRecordPool(threadobject *thread, int size)
-{
- lockRecordPool *p = mem_alloc(sizeof(lockRecordPoolHeader) + sizeof(monitorLockRecord) * size);
- int i;
+ if (isdaemon)
+ thread->flags |= THREAD_FLAG_DAEMON;
+
+#if defined(ENABLE_INTRP)
+ /* create interpreter stack */
- p->header.size = size;
- for (i=0; i<size; i++) {
- initLockRecord(&p->lr[i], thread);
- p->lr[i].nextFree = &p->lr[i+1];
+ if (opt_intrp) {
+ MSET(intrp_main_stack, 0, u1, opt_stacksize);
+ thread->_global_sp = (Cell *) (intrp_main_stack + opt_stacksize);
}
- p->lr[i-1].nextFree = NULL;
- return p;
-}
+#endif
-#define INITIALLOCKRECORDS 8
+#if defined(WITH_CLASSPATH_GNU)
+ /* create a java.lang.VMThread object */
-pthread_mutex_t pool_lock;
-lockRecordPool *global_pool;
+ vmt = (java_lang_VMThread *) builtin_new(class_java_lang_VMThread);
-static void initPools()
-{
- pthread_mutex_init(&pool_lock, NULL);
-}
+ if (vmt == NULL)
+ return false;
-static lockRecordPool *allocLockRecordPool(threadobject *t, int size)
-{
- pthread_mutex_lock(&pool_lock);
- if (global_pool) {
- int i;
- lockRecordPool *pool = global_pool;
- global_pool = pool->header.next;
- pthread_mutex_unlock(&pool_lock);
-
- for (i=0; i < pool->header.size; i++)
- pool->lr[i].ownerThread = t;
-
- return pool;
+ /* 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) {
+ u = utf_new_char(vm_aargs->name);
+#if defined(ENABLE_JAVASE)
+ group = (java_lang_ThreadGroup *) vm_aargs->group;
+#endif
+ }
+ else {
+ u = utf_null;
+#if defined(ENABLE_JAVASE)
+ group = mainthreadobj->object->group;
+#endif
}
- pthread_mutex_unlock(&pool_lock);
- return allocNewLockRecordPool(t, size);
-}
+ s = javastring_new(u);
-static void freeLockRecordPools(lockRecordPool *pool)
-{
- lockRecordPoolHeader *last;
- pthread_mutex_lock(&pool_lock);
- last = &pool->header;
- while (last->next)
- last = &last->next->header;
- last->next = global_pool;
- global_pool = pool;
- pthread_mutex_unlock(&pool_lock);
-}
+ o = (java_objectheader *) thread->object;
-static monitorLockRecord *allocLockRecordSimple(threadobject *t)
-{
- monitorLockRecord *r = t->ee.firstLR;
-
- if (!r) {
- int poolsize = t->ee.numlr ? t->ee.numlr * 2 : INITIALLOCKRECORDS;
- lockRecordPool *pool = allocLockRecordPool(t, poolsize);
- pool->header.next = t->ee.lrpool;
- t->ee.lrpool = pool;
- r = &pool->lr[0];
- t->ee.numlr += pool->header.size;
- }
-
- t->ee.firstLR = r->nextFree;
- return r;
-}
+#if defined(WITH_CLASSPATH_GNU)
+ (void) vm_call_method(method_thread_init, o, vmt, s, NORM_PRIORITY,
+ isdaemon);
+#elif defined(WITH_CLASSPATH_CLDC1_1)
+ (void) vm_call_method(method_thread_init, o, s);
+#endif
-static inline void recycleLockRecord(threadobject *t, monitorLockRecord *r)
-{
- r->nextFree = t->ee.firstLR;
- t->ee.firstLR = r;
-}
+ if (*exceptionptr)
+ return false;
-void initObjectLock(java_objectheader *o)
-{
- o->monitorPtr = dummyLR;
+#if defined(ENABLE_JAVASE)
+ /* store the thread group in the object */
+
+ thread->object->group = group;
+
+ /* add thread to given thread-group */
+
+ m = class_resolveclassmethod(group->header.vftbl->class,
+ utf_addThread,
+ utf_java_lang_Thread__V,
+ class_java_lang_ThreadGroup,
+ true);
+
+ o = (java_objectheader *) group;
+
+ (void) vm_call_method(m, o, t);
+
+ if (*exceptionptr)
+ return false;
+#endif
+
+ return true;
}
-/* get_dummyLR *****************************************************************
+/* threads_detach_thread *******************************************************
- Returns the global dummy monitor lock record. The pointer is
- required in the code generator to set up a virtual
- java_objectheader for code patch locking.
+ Detaches the passed thread from the VM. Used in JNI.
*******************************************************************************/
-monitorLockRecord *get_dummyLR(void)
+bool threads_detach_thread(threadobject *thread)
{
- return dummyLR;
-}
+#if defined(ENABLE_JAVASE)
+ java_lang_ThreadGroup *group;
+ methodinfo *m;
+ java_objectheader *o;
+ java_lang_Thread *t;
+#endif
+ /* Allow lock record pools to be used by other threads. They
+ cannot be deleted so we'd better not waste them. */
-static void queueOnLockRecord(monitorLockRecord *lr, java_objectheader *o)
-{
- atomic_add(&lr->queuers, 1);
+ /* XXX We have to find a new way to free lock records */
+ /* with the new locking algorithm. */
+ /* lock_record_free_pools(thread->ee.lockrecordpools); */
- MEMORY_BARRIER_AFTER_ATOMIC();
+ /* XXX implement uncaught exception stuff (like JamVM does) */
- while (lr->o == o)
- sem_wait(&lr->queueSem);
+#if defined(ENABLE_JAVASE)
+ /* remove thread from the thread group */
- atomic_add(&lr->queuers, -1);
-}
+ group = thread->object->group;
-static void freeLockRecord(monitorLockRecord *lr)
-{
- int q;
- lr->o = NULL;
- MEMORY_BARRIER();
- q = lr->queuers;
- while (q--)
- sem_post(&lr->queueSem);
-}
+ /* XXX TWISTI: should all threads be in a ThreadGroup? */
-static inline void handleWaiter(monitorLockRecord *mlr, monitorLockRecord *lr)
-{
- if (lr->waiting)
- mlr->waiter = lr;
-}
+ if (group != NULL) {
+ m = class_resolveclassmethod(group->header.vftbl->class,
+ utf_removeThread,
+ utf_java_lang_Thread__V,
+ class_java_lang_ThreadGroup,
+ true);
-monitorLockRecord *monitorEnter(threadobject *t, java_objectheader *o)
-{
- for (;;) {
- monitorLockRecord *lr = o->monitorPtr;
- if (lr->o != o) {
- monitorLockRecord *nlr, *mlr = allocLockRecordSimple(t);
- mlr->o = o;
- if (mlr == lr) {
- MEMORY_BARRIER();
- nlr = o->monitorPtr;
- if (nlr == lr) {
- handleWaiter(mlr, lr);
- return mlr;
- }
- } else {
- if (lr->ownerThread != t)
- mlr->incharge = lr;
- MEMORY_BARRIER_BEFORE_ATOMIC();
- nlr = (void*) compare_and_swap((long*) &o->monitorPtr, (long) lr, (long) mlr);
- }
- if (nlr == lr) {
- if (mlr == lr || lr->o != o) {
- handleWaiter(mlr, lr);
- return mlr;
- }
- while (lr->o == o)
- queueOnLockRecord(lr, o);
- handleWaiter(mlr, lr);
- return mlr;
- }
- freeLockRecord(mlr);
- recycleLockRecord(t, mlr);
- queueOnLockRecord(nlr, o);
- } else {
- if (lr->ownerThread == t) {
- lr->lockCount++;
- return lr;
- }
- queueOnLockRecord(lr, o);
- }
+ if (m == NULL)
+ return false;
+
+ o = (java_objectheader *) group;
+ t = thread->object;
+
+ (void) vm_call_method(m, o, t);
+
+ if (*exceptionptr)
+ return false;
}
-}
+#endif
-static void wakeWaiters(monitorLockRecord *lr)
-{
- monitorLockRecord *tmplr;
- s4 q;
+ /* remove thread from thread list and threads table, do this
+ inside a lock */
- /* assign lock record to a temporary variable */
+ pthread_mutex_lock(&threadlistlock);
- tmplr = lr;
+ thread->next->prev = thread->prev;
+ thread->prev->next = thread->next;
- do {
- q = tmplr->queuers;
+ threads_table_remove(thread);
+
+ pthread_mutex_unlock(&threadlistlock);
+
+ /* reset thread id (lock on joinmutex? TWISTI) */
+
+ pthread_mutex_lock(&(thread->joinmutex));
+ thread->tid = 0;
+ pthread_mutex_unlock(&(thread->joinmutex));
+
+ /* tell everyone that a thread has finished */
+
+ pthread_cond_broadcast(&(thread->joincond));
- while (q--)
- sem_post(&tmplr->queueSem);
+ /* free the vm internal thread object */
- tmplr = tmplr->waiter;
- } while (tmplr != NULL && tmplr != lr);
+ FREE(thread, threadobject);
+
+ return true;
}
-#define GRAB_LR(lr,t) \
- if (lr->ownerThread != t) { \
- lr = lr->incharge; \
- }
-#define CHECK_MONITORSTATE(lr,t,mo,a) \
- if (lr == NULL || lr->o != mo || lr->ownerThread != t) { \
- *exceptionptr = new_illegalmonitorstateexception(); \
- a; \
- }
+/* threads_find_non_daemon_thread **********************************************
+
+ Helper function used by threads_join_all_threads for finding
+ non-daemon threads that are still running.
+
+*******************************************************************************/
-bool monitorExit(threadobject *t, java_objectheader *o)
+/* 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)
{
- monitorLockRecord *lr = o->monitorPtr;
- GRAB_LR(lr, t);
- CHECK_MONITORSTATE(lr, t, o, return false);
- if (lr->lockCount > 1) {
- lr->lockCount--;
- return true;
- }
- if (lr->waiter) {
- monitorLockRecord *wlr = lr->waiter;
- if (o->monitorPtr != lr ||
- (void*) compare_and_swap((long*) &o->monitorPtr, (long) lr, (long) wlr) != lr)
- {
- monitorLockRecord *nlr = o->monitorPtr;
- nlr->waiter = wlr;
- STORE_ORDER_BARRIER();
- } else
- wakeWaiters(wlr);
- lr->waiter = NULL;
+ while (thread != mainthreadobj) {
+ if (!(thread->flags & THREAD_FLAG_DAEMON))
+ return thread;
+
+ thread = thread->prev;
}
- freeLockRecord(lr);
- recycleLockRecord(t, lr);
- return true;
+
+ return NULL;
}
-static void removeFromWaiters(monitorLockRecord *lr, monitorLockRecord *wlr)
+
+/* threads_join_all_threads ****************************************************
+
+ Join all non-daemon threads.
+
+*******************************************************************************/
+
+void threads_join_all_threads(void)
{
- do {
- if (lr->waiter == wlr) {
- lr->waiter = wlr->waiter;
- break;
- }
- lr = lr->waiter;
- } while (lr);
+ threadobject *thread;
+
+ pthread_mutex_lock(&threadlistlock);
+
+ while ((thread = threads_find_non_daemon_thread(mainthreadobj->prev)) != NULL) {
+ pthread_mutex_lock(&(thread->joinmutex));
+
+ pthread_mutex_unlock(&threadlistlock);
+
+ while (thread->tid)
+ pthread_cond_wait(&(thread->joincond), &(thread->joinmutex));
+
+ pthread_mutex_unlock(&(thread->joinmutex));
+
+ pthread_mutex_lock(&threadlistlock);
+ }
+
+ pthread_mutex_unlock(&threadlistlock);
}
-static inline bool timespec_less(const struct timespec *tv1, const struct timespec *tv2)
+
+/* threads_timespec_earlier ****************************************************
+
+ Return true if timespec tv1 is earlier than timespec tv2.
+
+ IN:
+ tv1..........first timespec
+ tv2..........second timespec
+
+ RETURN VALUE:
+ true, if the first timespec is earlier
+
+*******************************************************************************/
+
+static inline bool threads_timespec_earlier(const struct timespec *tv1,
+ const struct timespec *tv2)
{
- return tv1->tv_sec < tv2->tv_sec || (tv1->tv_sec == tv2->tv_sec && tv1->tv_nsec < tv2->tv_nsec);
+ return (tv1->tv_sec < tv2->tv_sec)
+ ||
+ (tv1->tv_sec == tv2->tv_sec && tv1->tv_nsec < tv2->tv_nsec);
}
-static bool timeIsEarlier(const struct timespec *tv)
+
+/* threads_current_time_is_earlier_than ****************************************
+
+ Check if the current time is earlier than the given timespec.
+
+ IN:
+ tv...........the timespec to compare against
+
+ RETURN VALUE:
+ true, if the current time is earlier
+
+*******************************************************************************/
+
+static bool threads_current_time_is_earlier_than(const struct timespec *tv)
{
struct timeval tvnow;
struct timespec tsnow;
- gettimeofday(&tvnow, NULL);
+
+ /* get current time */
+
+ if (gettimeofday(&tvnow, NULL) != 0)
+ vm_abort("gettimeofday failed: %s\n", strerror(errno));
+
+ /* convert it to a timespec */
+
tsnow.tv_sec = tvnow.tv_sec;
tsnow.tv_nsec = tvnow.tv_usec * 1000;
- return timespec_less(&tsnow, tv);
+
+ /* compare current time with the given timespec */
+
+ return threads_timespec_earlier(&tsnow, tv);
}
-/* waitWithTimeout *************************************************************
+/* threads_wait_with_timeout ***************************************************
+
+ Wait until the given point in time on a monitor until either
+ we are notified, we are interrupted, or the time is up.
+
+ IN:
+ t............the current thread
+ wakeupTime...absolute (latest) wakeup time
+ If both tv_sec and tv_nsec are zero, this function
+ waits for an unlimited amount of time.
- XXX
+ RETURN VALUE:
+ true.........if the wait has been interrupted,
+ false........if the wait was ended by notification or timeout
*******************************************************************************/
-static bool waitWithTimeout(threadobject *t, monitorLockRecord *lr, struct timespec *wakeupTime)
+static bool threads_wait_with_timeout(threadobject *thread,
+ struct timespec *wakeupTime)
{
bool wasinterrupted;
- pthread_mutex_lock(&t->waitLock);
+ /* acquire the waitmutex */
- t->isSleeping = true;
+ pthread_mutex_lock(&thread->waitmutex);
- if (wakeupTime->tv_sec || wakeupTime->tv_nsec)
- while (!t->interrupted && !t->signaled && timeIsEarlier(wakeupTime))
- pthread_cond_timedwait(&t->waitCond, &t->waitLock, wakeupTime);
- else
- while (!t->interrupted && !t->signaled)
- pthread_cond_wait(&t->waitCond, &t->waitLock);
+ /* mark us as sleeping */
+
+ thread->sleeping = true;
- wasinterrupted = t->interrupted;
- t->interrupted = false;
- t->signaled = false;
- t->isSleeping = false;
+ /* wait on waitcond */
- pthread_mutex_unlock(&t->waitLock);
+ if (wakeupTime->tv_sec || wakeupTime->tv_nsec) {
+ /* with timeout */
+ while (!thread->interrupted && !thread->signaled
+ && threads_current_time_is_earlier_than(wakeupTime))
+ {
+ pthread_cond_timedwait(&thread->waitcond, &thread->waitmutex,
+ wakeupTime);
+ }
+ }
+ else {
+ /* no timeout */
+ while (!thread->interrupted && !thread->signaled)
+ pthread_cond_wait(&thread->waitcond, &thread->waitmutex);
+ }
+
+ /* check if we were interrupted */
+
+ wasinterrupted = thread->interrupted;
+
+ /* reset all flags */
+
+ thread->interrupted = false;
+ thread->signaled = false;
+ thread->sleeping = false;
+
+ /* release the waitmutex */
+
+ pthread_mutex_unlock(&thread->waitmutex);
return wasinterrupted;
}
-static void calcAbsoluteTime(struct timespec *tm, s8 millis, s4 nanos)
+/* threads_wait_with_timeout_relative ******************************************
+
+ Wait for the given maximum amount of time on a monitor until either
+ we are notified, we are interrupted, or the time is up.
+
+ IN:
+ t............the current thread
+ millis.......milliseconds to wait
+ nanos........nanoseconds to wait
+
+ RETURN VALUE:
+ true.........if the wait has been interrupted,
+ false........if the wait was ended by notification or timeout
+
+*******************************************************************************/
+
+bool threads_wait_with_timeout_relative(threadobject *thread, s8 millis,
+ s4 nanos)
+{
+ struct timespec wakeupTime;
+
+ /* calculate the the (latest) wakeup time */
+
+ threads_calc_absolute_time(&wakeupTime, millis, nanos);
+
+ /* wait */
+
+ return threads_wait_with_timeout(thread, &wakeupTime);
+}
+
+
+/* threads_calc_absolute_time **************************************************
+
+ Calculate the absolute point in time a given number of ms and ns from now.
+
+ IN:
+ millis............milliseconds from now
+ nanos.............nanoseconds from now
+
+ OUT:
+ *tm...............receives the timespec of the absolute point in time
+
+*******************************************************************************/
+
+static void threads_calc_absolute_time(struct timespec *tm, s8 millis, s4 nanos)
{
- if (millis || nanos) {
+ if ((millis != 0x7fffffffffffffffLLU) && (millis || nanos)) {
struct timeval tv;
long nsec;
gettimeofday(&tv, NULL);
nsec = tv.tv_usec * 1000 + (s4) millis * 1000000 + nanos;
tm->tv_sec = tv.tv_sec + nsec / 1000000000;
tm->tv_nsec = nsec % 1000000000;
- } else {
+ }
+ else {
tm->tv_sec = 0;
tm->tv_nsec = 0;
}
}
-void monitorWait(threadobject *t, java_objectheader *o, s8 millis, s4 nanos)
-{
- bool wasinterrupted;
- struct timespec wakeupTime;
- monitorLockRecord *mlr, *lr = o->monitorPtr;
- GRAB_LR(lr, t);
- CHECK_MONITORSTATE(lr, t, o, return);
- calcAbsoluteTime(&wakeupTime, millis, nanos);
-
- if (lr->waiter)
- wakeWaiters(lr->waiter);
- lr->waiting = true;
- STORE_ORDER_BARRIER();
- freeLockRecord(lr);
- wasinterrupted = waitWithTimeout(t, lr, &wakeupTime);
- mlr = monitorEnter(t, o);
- removeFromWaiters(mlr, lr);
- mlr->lockCount = lr->lockCount;
- lr->lockCount = 1;
- lr->waiting = false;
- lr->waiter = NULL;
- recycleLockRecord(t, lr);
+/* threads_thread_interrupt ****************************************************
- if (wasinterrupted)
- *exceptionptr = new_exception(string_java_lang_InterruptedException);
-}
+ Interrupt the given thread.
-static void notifyOneOrAll(threadobject *t, java_objectheader *o, bool one)
-{
- monitorLockRecord *lr = o->monitorPtr;
- GRAB_LR(lr, t);
- CHECK_MONITORSTATE(lr, t, o, return);
- do {
- threadobject *wthread;
- monitorLockRecord *wlr = lr->waiter;
- if (!wlr)
- break;
- wthread = wlr->ownerThread;
- pthread_mutex_lock(&wthread->waitLock);
- if (wthread->isSleeping)
- pthread_cond_signal(&wthread->waitCond);
- wthread->signaled = true;
- pthread_mutex_unlock(&wthread->waitLock);
- lr = wlr;
- } while (!one);
-}
+ The thread gets the "waitcond" signal and
+ its interrupted flag is set to true.
-bool threadHoldsLock(threadobject *t, java_objectheader *o)
-{
- monitorLockRecord *lr = o->monitorPtr;
- GRAB_LR(lr, t);
- /* The reason why we have to check against NULL is that
- * dummyLR->incharge == NULL */
- return lr && lr->o == o && lr->ownerThread == t;
-}
+ IN:
+ thread............the thread to interrupt
+
+*******************************************************************************/
-void interruptThread(java_lang_VMThread *thread)
+void threads_thread_interrupt(threadobject *thread)
{
- threadobject *t = (threadobject*) thread;
+ /* Signal the thread a "waitcond" and tell it that it has been
+ interrupted. */
+
+ pthread_mutex_lock(&thread->waitmutex);
+
+ /* Interrupt blocking system call using a signal. */
+
+ pthread_kill(thread->tid, SIGHUP);
- t->interrupted = true;
- pthread_mutex_lock(&t->waitLock);
- if (t->isSleeping)
- pthread_cond_signal(&t->waitCond);
- pthread_mutex_unlock(&t->waitLock);
+ if (thread->sleeping)
+ pthread_cond_signal(&thread->waitcond);
+
+ thread->interrupted = true;
+
+ pthread_mutex_unlock(&thread->waitmutex);
}
-bool interruptedThread()
+
+/* threads_check_if_interrupted_and_reset **************************************
+
+ Check if the current thread has been interrupted and reset the
+ interruption flag.
+
+ RETURN VALUE:
+ true, if the current thread had been interrupted
+
+*******************************************************************************/
+
+bool threads_check_if_interrupted_and_reset(void)
{
- threadobject *t = (threadobject*) THREADOBJECT;
- bool intr = t->interrupted;
- t->interrupted = false;
+ threadobject *thread;
+ bool intr;
+
+ thread = THREADOBJECT;
+
+ /* get interrupted flag */
+
+ intr = thread->interrupted;
+
+ /* reset interrupted flag */
+
+ thread->interrupted = false;
+
return intr;
}
-bool isInterruptedThread(java_lang_VMThread *thread)
+
+/* threads_thread_has_been_interrupted *****************************************
+
+ Check if the given thread has been interrupted
+
+ IN:
+ t............the thread to check
+
+ RETURN VALUE:
+ true, if the given thread had been interrupted
+
+*******************************************************************************/
+
+bool threads_thread_has_been_interrupted(threadobject *thread)
{
- threadobject *t = (threadobject*) thread;
- return t->interrupted;
+ return thread->interrupted;
}
-void sleepThread(s8 millis, s4 nanos)
+
+/* threads_sleep ***************************************************************
+
+ Sleep the current thread for the specified amount of time.
+
+*******************************************************************************/
+
+void threads_sleep(s8 millis, s4 nanos)
{
- bool wasinterrupted;
- threadobject *t = (threadobject*) THREADOBJECT;
- monitorLockRecord *lr;
- struct timespec wakeupTime;
- calcAbsoluteTime(&wakeupTime, millis, nanos);
+ threadobject *thread;
+ struct timespec wakeupTime;
+ bool wasinterrupted;
+
+ thread = THREADOBJECT;
- lr = allocLockRecordSimple(t);
- wasinterrupted = waitWithTimeout(t, lr, &wakeupTime);
- recycleLockRecord(t, lr);
+ threads_calc_absolute_time(&wakeupTime, millis, nanos);
+
+ wasinterrupted = threads_wait_with_timeout(thread, &wakeupTime);
if (wasinterrupted)
- *exceptionptr = new_exception(string_java_lang_InterruptedException);
+ exceptions_throw_interruptedexception();
}
-void yieldThread()
-{
- sched_yield();
-}
-void setPriorityThread(thread *t, s4 priority)
-{
- nativethread *info = &((threadobject*) t->vmThread)->info;
- setPriority(info->tid, priority);
-}
+/* threads_yield ***************************************************************
-void wait_cond_for_object(java_objectheader *o, s8 time, s4 nanos)
-{
- threadobject *t = (threadobject*) THREADOBJECT;
- monitorWait(t, o, time, nanos);
-}
+ Yield to the scheduler.
-void signal_cond_for_object(java_objectheader *o)
-{
- threadobject *t = (threadobject*) THREADOBJECT;
- notifyOneOrAll(t, o, true);
-}
+*******************************************************************************/
-void broadcast_cond_for_object(java_objectheader *o)
+void threads_yield(void)
{
- threadobject *t = (threadobject*) THREADOBJECT;
- notifyOneOrAll(t, o, false);
+ sched_yield();
}
void threads_dump(void)
{
- threadobject *tobj;
- java_lang_VMThread *vmt;
- nativethread *nt;
- ExecEnvironment *ee;
- java_lang_Thread *t;
- utf *name;
+ threadobject *thread;
+ java_lang_Thread *t;
+ utf *name;
+
+ thread = mainthreadobj;
- tobj = mainthreadobj;
+ /* XXX we should stop the world here */
printf("Full thread dump CACAO "VERSION":\n");
/* iterate over all started threads */
do {
- /* get thread objects */
+ /* get thread object */
- vmt = &tobj->o;
- nt = &tobj->info;
- ee = &tobj->ee;
- t = vmt->thread;
+ t = thread->object;
/* the thread may be currently in initalization, don't print it */
- if (t) {
+ 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(name);
+ utf_display_printable_ascii(name);
printf("\" ");
- if (t->daemon)
+ if (thread->flags & THREAD_FLAG_DAEMON)
printf("daemon ");
#if SIZEOF_VOID_P == 8
- printf("prio=%d tid=0x%016lx\n", t->priority, nt->tid);
+ printf("prio=%d tid=0x%016lx\n", t->priority, (ptrint) thread->tid);
#else
- printf("prio=%d tid=0x%08lx\n", t->priority, nt->tid);
+ printf("prio=%d tid=0x%08lx\n", t->priority, (ptrint) thread->tid);
#endif
- /* send SIGUSR1 to thread to print stacktrace */
+ /* dump trace of thread */
+
+ stacktrace_dump_trace(thread);
+ }
+
+ thread = thread->next;
+ } while ((thread != NULL) && (thread != mainthreadobj));
+}
- pthread_kill(nt->tid, SIGUSR1);
- /* sleep this thread a bit, so the signal can reach the thread */
+/* threads_table_dump *********************************************************
+
+ Dump the threads table for debugging purposes.
+
+ IN:
+ file..............stream to write to
+
+******************************************************************************/
+
+#if !defined(NDEBUG) && 0
+static void threads_table_dump(FILE *file)
+{
+ s4 i;
+ s4 size;
+ ptrint index;
- sleepThread(10, 0);
+ pthread_mutex_lock(&threadlistlock);
+
+ size = threads_table.size;
+
+ fprintf(file, "======== THREADS TABLE (size %d) ========\n", size);
+
+ for (i=0; i<size; ++i) {
+ index = threads_table.table[i].nextfree;
+
+ fprintf(file, "%4d: ", i);
+
+ if (index < size) {
+ fprintf(file, "free, nextfree = %d\n", (int) index);
}
+ else {
+ fprintf(file, "thread %p\n", (void*) threads_table.table[i].thread);
+ }
+ }
- tobj = tobj->info.next;
- } while (tobj && (tobj != mainthreadobj));
-}
+ fprintf(file, "======== END OF THREADS TABLE ========\n");
+ pthread_mutex_unlock(&threadlistlock);
+}
+#endif
/*
* These are local overrides for various environment variables in Emacs.
* c-basic-offset: 4
* tab-width: 4
* End:
+ * vim:noexpandtab:sw=4:ts=4:
*/