-#include "global.h"
+/* 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
+
+ This file is part of CACAO.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ 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.
+
+ Contact: cacao@complang.tuwien.ac.at
+
+ Authors: Stefan Ring
+
+ $Id: threads.c 1735 2004-12-07 14:33:27Z twisti $
+
+*/
-#if defined(NATIVE_THREADS)
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <errno.h>
-#include "config.h"
-#include "thread.h"
#include "codegen.h"
-#include "locks.h"
-#include "tables.h"
-#include "native.h"
-#include "loader.h"
-#include "builtin.h"
-#include "asmpart.h"
-#include "toolbox/logging.h"
-#include "toolbox/memory.h"
-#include "toolbox/avl.h"
+#include "config.h"
#include "mm/boehm.h"
-
-#include "nat/java_lang_Object.h"
-#include "nat/java_lang_Throwable.h"
-#include "nat/java_lang_Thread.h"
-#include "nat/java_lang_ThreadGroup.h"
+#include "mm/memory.h"
+#include "native/native.h"
+#include "native/include/java_lang_Object.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"
+#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/tables.h"
+#include "vm/jit/asmpart.h"
#include <pthread.h>
#include <semaphore.h>
+#if !defined(__DARWIN__)
#if defined(__LINUX__)
#define GC_LINUX_THREADS
-#include "../mm/boehm-gc/include/gc.h"
+#elif defined(__MIPS__)
+#define GC_IRIX_THREADS
+#endif
+#include "boehm-gc/include/gc.h"
#endif
+#ifdef MUTEXSIM
+
+/* We need this for older MacOSX (10.1.x) */
+
+typedef struct {
+ pthread_mutex_t mutex;
+ pthread_t owner;
+ int count;
+} pthread_mutex_rec_t;
+
+static void pthread_mutex_init_rec(pthread_mutex_rec_t *m)
+{
+ pthread_mutex_init(&m->mutex, NULL);
+ m->count = 0;
+}
+
+static void pthread_mutex_destroy_rec(pthread_mutex_rec_t *m)
+{
+ pthread_mutex_destroy(&m->mutex);
+}
+
+static void pthread_mutex_lock_rec(pthread_mutex_rec_t *m)
+{
+ 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;
+ }
+ }
+}
+
+static void pthread_mutex_unlock_rec(pthread_mutex_rec_t *m)
+{
+ if (!--m->count)
+ pthread_mutex_unlock(&m->mutex);
+}
+
+#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
+
+#endif /* MUTEXSIM */
+
+static void setPriority(pthread_t tid, int priority)
+{
+ struct sched_param schedp;
+ int policy;
+
+ pthread_getschedparam(tid, &policy, &schedp);
+ schedp.sched_priority = priority;
+ pthread_setschedparam(tid, policy, &schedp);
+}
+
#include "machine-instr.h"
static struct avl_table *criticaltree;
__thread threadobject *threadobj;
#endif
-static pthread_mutex_t cast_mutex = PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP;
-static pthread_mutex_t compiler_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
-static pthread_mutex_t tablelock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
-
-void cast_lock()
-{
- pthread_mutex_lock(&cast_mutex);
-}
-
-void cast_unlock()
-{
- pthread_mutex_unlock(&cast_mutex);
-}
+static pthread_mutex_rec_t compiler_mutex;
+static pthread_mutex_rec_t tablelock;
void compiler_lock()
{
- pthread_mutex_lock(&compiler_mutex);
+ pthread_mutex_lock_rec(&compiler_mutex);
}
void compiler_unlock()
{
- pthread_mutex_unlock(&compiler_mutex);
+ pthread_mutex_unlock_rec(&compiler_mutex);
}
void tables_lock()
{
- pthread_mutex_lock(&tablelock);
+ pthread_mutex_lock_rec(&tablelock);
}
void tables_unlock()
{
- pthread_mutex_unlock(&tablelock);
+ pthread_mutex_unlock_rec(&tablelock);
}
static int criticalcompare(const void *pa, const void *pb, void *param)
return (n && mcodeptr < n->mcodeend && mcodeptr > n->mcodebegin) ? n->mcoderestart : NULL;
}
-static pthread_mutex_t threadlistlock = PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP;
+static void thread_addstaticcritical()
+{
+ threadcritnode *n = &asm_criticalsections;
-static pthread_mutex_t stopworldlock = PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP;
+ while (n->mcodebegin)
+ thread_registercritical(n++);
+}
+
+static pthread_mutex_t threadlistlock;
+
+static pthread_mutex_t stopworldlock;
volatile int stopworldwhere;
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
pthread_mutex_unlock(&stopworldlock);
}
+#if !defined(__DARWIN__)
/* Caller must hold threadlistlock */
static int cast_sendsignals(int sig, int count)
{
return count-1;
}
+#else
+
+static void cast_darwinstop()
+{
+ threadobject *tobj = mainthreadobj;
+ nativethread *infoself = THREADINFO;
+
+ do {
+ nativethread *info = &tobj->info;
+ if (info != infoself)
+ {
+ thread_state_flavor_t flavor = PPC_THREAD_STATE;
+ mach_msg_type_number_t thread_state_count = PPC_THREAD_STATE_COUNT;
+ ppc_thread_state_t thread_state;
+ mach_port_t thread = info->mach_thread;
+ kern_return_t r;
+
+ r = thread_suspend(thread);
+ if (r != KERN_SUCCESS)
+ panic("thread_suspend failed");
+
+ r = thread_get_state(thread, flavor,
+ (natural_t*)&thread_state, &thread_state_count);
+ if (r != KERN_SUCCESS)
+ panic("thread_get_state failed");
+
+ thread_restartcriticalsection(&thread_state);
+
+ r = thread_set_state(thread, flavor,
+ (natural_t*)&thread_state, thread_state_count);
+ if (r != KERN_SUCCESS)
+ panic("thread_set_state failed");
+ }
+ tobj = tobj->info.next;
+ } while (tobj != mainthreadobj);
+}
+
+static void cast_darwinresume()
+{
+ threadobject *tobj = mainthreadobj;
+ nativethread *infoself = THREADINFO;
+
+ do {
+ nativethread *info = &tobj->info;
+ if (info != infoself)
+ {
+ mach_port_t thread = info->mach_thread;
+ kern_return_t r;
+
+ r = thread_resume(thread);
+ if (r != KERN_SUCCESS)
+ panic("thread_resume failed");
+ }
+ tobj = tobj->info.next;
+ } while (tobj != mainthreadobj);
+}
+
+#endif
+
+#if defined(__MIPS__)
+static void cast_irixresume()
+{
+ pthread_mutex_lock(&suspend_ack_lock);
+ pthread_cond_broadcast(&suspend_cond);
+ pthread_mutex_unlock(&suspend_ack_lock);
+}
+#endif
+
void cast_stopworld()
{
int count, i;
lock_stopworld(2);
pthread_mutex_lock(&threadlistlock);
+#if defined(__DARWIN__)
+ cast_darwinstop();
+#else
count = cast_sendsignals(GC_signum1(), 0);
for (i=0; i<count; i++)
sem_wait(&suspend_ack);
+#endif
pthread_mutex_unlock(&threadlistlock);
}
void cast_startworld()
{
pthread_mutex_lock(&threadlistlock);
+#if defined(__DARWIN__)
+ cast_darwinresume();
+#elif defined(__MIPS__)
+ cast_irixresume();
+#else
cast_sendsignals(GC_signum2(), -1);
+#endif
pthread_mutex_unlock(&threadlistlock);
unlock_stopworld();
}
+#if !defined(__DARWIN__)
static void sigsuspend_handler(ucontext_t *ctx)
{
int sig;
thread_restartcriticalsection(ctx);
+ /* 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);
+ pthread_cond_wait(&suspend_cond, &suspend_ack_lock);
+ pthread_mutex_unlock(&suspend_ack_lock);
+#else
sem_post(&suspend_ack);
sig = GC_signum2();
sigfillset(&sigs);
sigdelset(&sigs, sig);
sigsuspend(&sigs);
+#endif
}
int cacao_suspendhandler(ucontext_t *ctx)
sigsuspend_handler(ctx);
return 1;
}
+#endif
static void setthreadobject(threadobject *thread)
{
#endif
}
+static monitorLockRecord *dummyLR;
+
+static void initPools();
+
/*
* Initialize threads.
*/
void
initThreadsEarly()
{
+#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);
- memset(mainthreadobj, 0, sizeof(threadobject));
+ mainthreadobj->info.tid = pthread_self();
#if !defined(HAVE___THREAD)
pthread_key_create(&tkey_threadinfo, NULL);
#endif
setthreadobject(mainthreadobj);
+ initPools();
criticaltree = avl_create(criticalcompare, NULL, NULL);
+ thread_addstaticcritical();
sem_init(&suspend_ack, 0, 0);
+
+ /* Every newly created object's monitorPtr points here so we save a check
+ * against NULL */
+ dummyLR = NEW(monitorLockRecord);
+ dummyLR->o = NULL;
+ dummyLR->ownerThread = NULL;
+ dummyLR->waiting = false;
}
static pthread_attr_t threadattr;
+
static void freeLockRecordPools(lockRecordPool *);
void
initThreads(u1 *stackbottom)
{
classinfo *threadclass;
- classinfo *threadgroupclass;
+ classinfo *threadgroupclass;
+ java_lang_String *threadname;
java_lang_Thread *mainthread;
+ java_lang_ThreadGroup *threadgroup;
threadobject *tempthread = mainthreadobj;
+ methodinfo *method;
- threadclass = class_new(utf_new_char("java/lang/Thread"));
+ threadclass = class_new(utf_new_char("java/lang/VMThread"));
class_load(threadclass);
class_link(threadclass);
- assert(threadclass);
+ if (!threadclass)
+ throw_exception_exit();
+
freeLockRecordPools(mainthreadobj->ee.lrpool);
+ /* 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 */
threadclass->instancesize = sizeof(threadobject);
+ /* Create a VMThread */
mainthreadobj = (threadobject *) builtin_new(threadclass);
- assert(mainthreadobj);
+
+ if (!mainthreadobj)
+ throw_exception_exit();
FREE(tempthread, threadobject);
initThread(&mainthreadobj->o);
-#if !defined(HAVE___THREAD)
- pthread_setspecific(tkey_threadinfo, mainthreadobj);
-#else
- threadobj = mainthreadobj;
-#endif
+ setthreadobject(mainthreadobj);
- mainthread = &mainthreadobj->o;
initLocks();
mainthreadobj->info.next = mainthreadobj;
mainthreadobj->info.prev = mainthreadobj;
- mainthread->name=javastring_new(utf_new_char("main"));
+ threadname = javastring_new(utf_new_char("main"));
/* Allocate and init ThreadGroup */
threadgroupclass = class_new(utf_new_char("java/lang/ThreadGroup"));
- class_load(threadgroupclass);
- class_link(threadgroupclass);
-
- mainthread->group =
+ threadgroup =
(java_lang_ThreadGroup *) native_new_and_init(threadgroupclass);
- assert(mainthread->group != 0);
+
+ if (!threadgroup)
+ throw_exception_exit();
+
+ /* Create a Thread */
+ threadclass = class_new(utf_new_char("java/lang/Thread"));
+ mainthread = (java_lang_Thread*) builtin_new(threadclass);
+ mainthreadobj->o.thread = mainthread;
+
+ if (!mainthread)
+ throw_exception_exit();
+
+ /* Call Thread constructor */
+ method = class_resolveclassmethod(threadclass,
+ utf_new_char("<init>"),
+ utf_new_char("(Ljava/lang/VMThread;Ljava/lang/String;IZ)V"),
+ threadclass,
+ true);
+
+ if (!method)
+ throw_exception_exit();
+
+ asm_calljavafunction(method, mainthread, mainthreadobj, threadname, (void*) 5);
+ if (*exceptionptr)
+ throw_exception_exit();
+
+ mainthread->group = threadgroup;
+ /* XXX This is a hack because the fourth argument was omitted */
+ mainthread->daemon = false;
+
+ /* Add mainthread to ThreadGroup */
+ method = class_resolveclassmethod(threadgroupclass,
+ utf_new_char("addThread"),
+ utf_new_char("(Ljava/lang/Thread;)V"),
+ threadgroupclass,
+ true);
+
+ if (!method)
+ throw_exception_exit();
+
+ asm_calljavafunction(method, threadgroup, mainthread, NULL, NULL);
+ if (*exceptionptr)
+ throw_exception_exit();
+
+ setPriority(pthread_self(), 5);
pthread_attr_init(&threadattr);
pthread_attr_setdetachstate(&threadattr, PTHREAD_CREATE_DETACHED);
}
-void initThread(java_lang_Thread *t)
+void initThread(java_lang_VMThread *t)
{
- nativethread *info = &((threadobject*) t)->info;
+ 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);
+
+ pthread_mutex_init(&thread->waitLock, NULL);
+ pthread_cond_init(&thread->waitCond, NULL);
+ thread->interrupted = false;
+ thread->signaled = false;
+ thread->isSleeping = false;
}
static void initThreadLocks(threadobject *);
static void *threadstartup(void *t)
{
startupinfo *startup = t;
- t = NULL;
threadobject *thread = startup->thread;
sem_t *psem = startup->psem;
nativethread *info = &thread->info;
threadobject *tnext;
methodinfo *method;
+ t = NULL;
+#if defined(__DARWIN__)
+ info->mach_thread = mach_thread_self();
+#endif
setthreadobject(thread);
pthread_mutex_lock(&threadlistlock);
startup = NULL;
sem_post(psem);
+ setPriority(info->tid, thread->o.thread->priority);
+ sched_yield();
+
/* Find the run()V method and call it */
- method = class_findmethod(thread->o.header.vftbl->class,
- utf_new_char("run"), utf_new_char("()V"));
- if (!method)
- panic("Cannot find method \'void run ()\'");
+ method = class_resolveclassmethod(thread->o.header.vftbl->class,
+ utf_new_char("run"),
+ utf_new_char("()V"),
+ thread->o.header.vftbl->class,
+ true);
- asm_calljavafunction(method, thread, NULL, NULL, NULL);
+ /* if method != NULL, we had not exception */
+ if (method) {
+ asm_calljavafunction(method, thread, NULL, NULL, NULL);
- if (info->_exceptionptr) {
- utf_display_classname((info->_exceptionptr)->vftbl->class->name);
- printf("\n");
- }
+ } else {
+ throw_exception();
+ }
+ /* Allow lock record pools to be used by other threads. They cannot be
+ * deleted so we'd better not waste them. */
freeLockRecordPools(thread->ee.lrpool);
pthread_mutex_lock(&threadlistlock);
return NULL;
}
-void startThread(threadobject *t)
+void startThread(thread *t)
{
- nativethread *info = &t->info;
+ nativethread *info = &((threadobject*) t->vmThread)->info;
sem_t sem;
startupinfo startup;
- startup.thread = t;
+ startup.thread = (threadobject*) t->vmThread;
startup.psem = &sem;
sem_init(&sem, 0, 0);
if (pthread_create(&info->tid, &threadattr, threadstartup, &startup))
panic("pthread_create failed");
- /* Wait here until thread has entered itself into the thread list */
+ /* Wait here until the thread has entered itself into the thread list */
sem_wait(&sem);
sem_destroy(&sem);
}
+/* At the end of the program, we wait for all running non-daemon threads to die
+ */
+
+static threadobject *findNonDaemon(threadobject *thread)
+{
+ while (thread != mainthreadobj) {
+ if (!thread->o.thread->daemon)
+ return thread;
+ thread = thread->info.prev;
+ }
+
+ return NULL;
+}
+
void joinAllThreads()
{
+ threadobject *thread;
pthread_mutex_lock(&threadlistlock);
- while (mainthreadobj->info.prev != mainthreadobj) {
- nativethread *info = &mainthreadobj->info.prev->info;
+ while ((thread = findNonDaemon(mainthreadobj->info.prev)) != NULL) {
+ nativethread *info = &thread->info;
pthread_mutex_lock(&info->joinMutex);
pthread_mutex_unlock(&threadlistlock);
- if (info->tid)
+ while (info->tid)
pthread_cond_wait(&info->joinCond, &info->joinMutex);
pthread_mutex_unlock(&info->joinMutex);
pthread_mutex_lock(&threadlistlock);
pthread_mutex_unlock(&threadlistlock);
}
-bool aliveThread(java_lang_Thread *t)
-{
- return ((threadobject*) t)->info.tid != 0;
-}
-
-void sleepThread(s8 millis)
-{
- struct timespec tv;
- tv.tv_sec = millis / 1000;
- tv.tv_nsec = millis % 1000 * 1000000;
- do { } while (nanosleep(&tv, &tv) == EINTR);
-}
-
-void yieldThread()
-{
- sched_yield();
-}
-
-static void timedCondWait(pthread_cond_t *cond, pthread_mutex_t *mutex, s8 millis)
+static void initLockRecord(monitorLockRecord *r, threadobject *t)
{
- struct timeval now;
- struct timespec desttime;
- gettimeofday(&now, NULL);
- desttime.tv_sec = millis / 1000;
- desttime.tv_nsec = millis % 1000 * 1000000;
- pthread_cond_timedwait(cond, mutex, &desttime);
+ 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);
}
+/* No lock record must ever be destroyed because there may still be references
+ * to it.
-#define NEUTRAL 0
-#define LOCKED 1
-#define WAITERS 2
-#define BUSY 3
-
-static void initExecutionEnvironment(ExecEnvironment *ee)
-{
- pthread_mutex_init(&ee->metaLockMutex, NULL);
- pthread_cond_init(&ee->metaLockCond, NULL);
- pthread_mutex_init(&ee->monitorLockMutex, NULL);
- pthread_cond_init(&ee->monitorLockCond, NULL);
-}
-
-static void initLockRecord(monitorLockRecord *r, threadobject *t)
+static void destroyLockRecord(monitorLockRecord *r)
{
- r->owner = t;
- r->lockCount = 1;
- r->queue = NULL;
+ sem_destroy(&r->queueSem);
+ pthread_mutex_destroy(&r->resolveLock);
+ pthread_cond_destroy(&r->resolveWait);
}
+*/
void initLocks()
{
static void initThreadLocks(threadobject *thread)
{
- int i;
-
- initExecutionEnvironment(&thread->ee);
- for (i=0; i<INITIALLOCKRECORDS; i++) {
- monitorLockRecord *r = &thread->ee.lr[i];
- initLockRecord(r, thread);
- r->nextFree = &thread->ee.lr[i+1];
- }
- thread->ee.lr[i-1].nextFree = NULL;
- thread->ee.firstLR = &thread->ee.lr[0];
-}
-
-static inline int lockState(long r)
-{
- return (int) r & 3;
-}
-
-static inline void *lockRecord(long r)
-{
- return (void*) (r & ~3L);
+ thread->ee.firstLR = NULL;
+ thread->ee.lrpool = NULL;
+ thread->ee.numlr = 0;
}
-static inline long makeLockBits(void *r, long l)
-{
- return ((long) r) | l;
-}
-
-static lockRecordPool *allocLockRecordPool(threadobject *thread, int size)
+static lockRecordPool *allocNewLockRecordPool(threadobject *thread, int size)
{
lockRecordPool *p = mem_alloc(sizeof(lockRecordPoolHeader) + sizeof(monitorLockRecord) * size);
int i;
return p;
}
-static void freeLockRecordPools(lockRecordPool *pool)
+#define INITIALLOCKRECORDS 8
+
+static pthread_mutex_t pool_lock;
+static lockRecordPool *global_pool;
+
+static void initPools()
{
- while (pool) {
- lockRecordPool *n = pool->header.next;
- mem_free(pool, sizeof(lockRecordPoolHeader) + sizeof(monitorLockRecord) * pool->header.size);
- pool = n;
+ pthread_mutex_init(&pool_lock, NULL);
+}
+
+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;
}
+ pthread_mutex_unlock(&pool_lock);
+
+ return allocNewLockRecordPool(t, size);
+}
+
+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);
}
-static monitorLockRecord *allocLockRecord(threadobject *t)
+static monitorLockRecord *allocLockRecordSimple(threadobject *t)
{
monitorLockRecord *r = t->ee.firstLR;
if (!r) {
- int poolsize = t->ee.lrpool ? t->ee.lrpool->header.size * 2 : INITIALLOCKRECORDS * 2;
+ 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;
}
-static void recycleLockRecord(threadobject *t, monitorLockRecord *r)
+static inline void recycleLockRecord(threadobject *t, monitorLockRecord *r)
{
r->nextFree = t->ee.firstLR;
t->ee.firstLR = r;
}
-static monitorLockRecord *appendToQueue(monitorLockRecord *queue, monitorLockRecord *lr)
+void initObjectLock(java_objectheader *o)
{
- monitorLockRecord *queuestart = queue;
- if (!queue)
- return lr;
- while (queue->queue)
- queue = queue->queue;
- queue->queue = lr;
- return queuestart;
+ o->monitorPtr = dummyLR;
}
-static monitorLockRecord *moveMyLRToFront(threadobject *t, monitorLockRecord *lr)
+static void queueOnLockRecord(monitorLockRecord *lr, java_objectheader *o)
{
- monitorLockRecord *pred = NULL;
- monitorLockRecord *firstLR = lr;
- while (lr->owner != t) {
- pred = lr;
- lr = lr->queue;
- }
- if (!pred)
- return lr;
- pred->queue = lr->queue;
- lr->queue = firstLR;
- lr->storedBits = firstLR->storedBits;
- return lr;
+ atomic_add(&lr->queuers, 1);
+ MEMORY_BARRIER_AFTER_ATOMIC();
+ while (lr->o == o)
+ sem_wait(&lr->queueSem);
+ atomic_add(&lr->queuers, -1);
}
-static long getMetaLockSlow(threadobject *t, long predBits);
-static void releaseMetaLockSlow(threadobject *t, long releaseBits);
+static void freeLockRecord(monitorLockRecord *lr)
+{
+ int q;
+ lr->o = NULL;
+ MEMORY_BARRIER();
+ q = lr->queuers;
+ while (q--)
+ sem_post(&lr->queueSem);
+}
-static long getMetaLock(threadobject *t, java_objectheader *o)
+static inline void handleWaiter(monitorLockRecord *mlr, monitorLockRecord *lr)
{
- long busyBits = makeLockBits(t, BUSY);
- long lockBits = atomic_swap(&o->monitorBits, busyBits);
- return lockState(lockBits) != BUSY ? lockBits : getMetaLockSlow(t, lockBits);
+ if (lr->waiting)
+ mlr->waiter = lr;
}
-static long getMetaLockSlow(threadobject *t, long predBits)
+monitorLockRecord *monitorEnter(threadobject *t, java_objectheader *o)
{
- long bits;
- threadobject *pred = lockRecord(predBits);
- pthread_mutex_lock(&pred->ee.metaLockMutex);
- if (!pred->ee.bitsForGrab) {
- pred->ee.succ = t;
- do {
- pthread_cond_wait(&pred->ee.metaLockCond, &pred->ee.metaLockMutex);
- } while (!t->ee.gotMetaLockSlow);
- t->ee.gotMetaLockSlow = false;
- bits = t->ee.metaLockBits;
- } else {
- bits = pred->ee.metaLockBits;
- pred->ee.bitsForGrab = false;
- pthread_cond_signal(&pred->ee.metaLockCond);
+ 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);
+ }
}
- pthread_mutex_unlock(&pred->ee.metaLockMutex);
- return bits;
}
-static void releaseMetaLock(threadobject *t, java_objectheader *o, long releaseBits)
+static void wakeWaiters(monitorLockRecord *lr)
{
- long busyBits = makeLockBits(t, BUSY);
- int locked = compare_and_swap(&o->monitorBits, busyBits, releaseBits) != 0;
-
- if (!locked)
- releaseMetaLockSlow(t, releaseBits);
+ do {
+ int q = lr->queuers;
+ while (q--)
+ sem_post(&lr->queueSem);
+ lr = lr->waiter;
+ } while (lr);
}
-static void releaseMetaLockSlow(threadobject *t, long releaseBits)
-{
- pthread_mutex_lock(&t->ee.metaLockMutex);
- if (t->ee.succ) {
- assert(!t->ee.succ->ee.bitsForGrab);
- assert(!t->ee.bitsForGrab);
- assert(!t->ee.succ->ee.gotMetaLockSlow);
- t->ee.succ->ee.metaLockBits = releaseBits;
- t->ee.succ->ee.gotMetaLockSlow = true;
- t->ee.succ = NULL;
- pthread_cond_signal(&t->ee.metaLockCond);
- } else {
- t->ee.metaLockBits = releaseBits;
- t->ee.bitsForGrab = true;
- do {
- pthread_cond_wait(&t->ee.metaLockCond, &t->ee.metaLockMutex);
- } while (t->ee.bitsForGrab);
+#define GRAB_LR(lr,t) \
+ if (lr->ownerThread != t) { \
+ lr = lr->incharge; \
}
- pthread_mutex_unlock(&t->ee.metaLockMutex);
-}
-static void monitorEnterSlow(threadobject *t, java_objectheader *o, long r);
+#define CHECK_MONITORSTATE(lr,t,mo,a) \
+ if (lr->o != mo || lr->ownerThread != t) { \
+ *exceptionptr = new_exception(string_java_lang_IllegalMonitorStateException); \
+ a; \
+ }
-void monitorEnter(threadobject *t, java_objectheader *o)
+bool monitorExit(threadobject *t, java_objectheader *o)
{
- long r = getMetaLock(t, o);
- int state = lockState(r);
-
- if (state == NEUTRAL) {
- monitorLockRecord *lr = allocLockRecord(t);
- lr->storedBits = r;
- releaseMetaLock(t, o, makeLockBits(lr, LOCKED));
- } else if (state == LOCKED) {
- monitorLockRecord *ownerLR = lockRecord(r);
- if (ownerLR->owner == t) {
- ownerLR->lockCount++;
- releaseMetaLock(t, o, r);
- } else {
- monitorLockRecord *lr = allocLockRecord(t);
- ownerLR->queue = appendToQueue(ownerLR->queue, lr);
- monitorEnterSlow(t, o, r);
- }
- } else if (state == WAITERS) {
- monitorLockRecord *lr = allocLockRecord(t);
- monitorLockRecord *firstWaiterLR = lockRecord(r);
- lr->queue = firstWaiterLR;
- lr->storedBits = firstWaiterLR->storedBits;
- releaseMetaLock(t, o, makeLockBits(lr, LOCKED));
+ 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;
+ }
+ freeLockRecord(lr);
+ recycleLockRecord(t, lr);
+ return true;
}
-static void monitorEnterSlow(threadobject *t, java_objectheader *o, long r)
+static void removeFromWaiters(monitorLockRecord *lr, monitorLockRecord *wlr)
{
- monitorLockRecord *lr;
- while (lockState(r) == LOCKED) {
- pthread_mutex_lock(&t->ee.monitorLockMutex);
- releaseMetaLock(t, o, r);
- pthread_cond_wait(&t->ee.monitorLockCond, &t->ee.monitorLockMutex);
- pthread_mutex_unlock(&t->ee.monitorLockMutex);
- r = getMetaLock(t, o);
- }
- assert(lockState(r) == WAITERS);
- lr = moveMyLRToFront(t, lockRecord(r));
- releaseMetaLock(t, o, makeLockBits(lr, LOCKED));
+ do {
+ if (lr->waiter == wlr) {
+ lr->waiter = wlr->waiter;
+ break;
+ }
+ lr = lr->waiter;
+ } while (lr);
}
-static void monitorExitSlow(threadobject *t, java_objectheader *o, monitorLockRecord *lr);
+static inline bool timespec_less(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);
+}
-void monitorExit(threadobject *t, java_objectheader *o)
+static bool timeIsEarlier(const struct timespec *tv)
{
- long r = getMetaLock(t, o);
- monitorLockRecord *ownerLR = lockRecord(r);
- int state = lockState(r);
- if (state == LOCKED && ownerLR->owner == t) {
- assert(ownerLR->lockCount >= 1);
- if (ownerLR->lockCount == 1) {
- if (ownerLR->queue == NULL) {
- assert(lockState(ownerLR->storedBits) == NEUTRAL);
- releaseMetaLock(t, o, ownerLR->storedBits);
- } else {
- ownerLR->queue->storedBits = ownerLR->storedBits;
- monitorExitSlow(t, o, ownerLR->queue);
- ownerLR->queue = NULL;
- }
- recycleLockRecord(t, ownerLR);
- } else {
- ownerLR->lockCount--;
- releaseMetaLock(t, o, r);
- }
- } else {
- releaseMetaLock(t, o, r);
- panic("Illegal monitor exception");
- }
+ struct timeval tvnow;
+ struct timespec tsnow;
+ gettimeofday(&tvnow, NULL);
+ tsnow.tv_sec = tvnow.tv_sec;
+ tsnow.tv_nsec = tvnow.tv_usec * 1000;
+ return timespec_less(&tsnow, tv);
}
-static threadobject *wakeupEE(monitorLockRecord *lr)
+bool waitWithTimeout(threadobject *t, monitorLockRecord *lr, struct timespec *wakeupTime)
{
- while (lr->queue && lr->queue->owner->ee.isWaitingForNotify)
- lr = lr->queue;
- return lr->owner;
+ bool wasinterrupted;
+
+ pthread_mutex_lock(&t->waitLock);
+ t->isSleeping = true;
+ 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);
+ wasinterrupted = t->interrupted;
+ t->interrupted = false;
+ t->signaled = false;
+ t->isSleeping = false;
+ pthread_mutex_unlock(&t->waitLock);
+ return wasinterrupted;
}
-static void monitorExitSlow(threadobject *t, java_objectheader *o, monitorLockRecord *lr)
+static void calcAbsoluteTime(struct timespec *tm, s8 millis, s4 nanos)
{
- threadobject *wakeEE = wakeupEE(lr);
- if (wakeEE) {
- pthread_mutex_lock(&wakeEE->ee.monitorLockMutex);
- releaseMetaLock(t, o, makeLockBits(lr, WAITERS));
- pthread_cond_signal(&wakeEE->ee.monitorLockCond);
- pthread_mutex_unlock(&wakeEE->ee.monitorLockMutex);
+ if (millis || nanos) {
+ struct timeval tv;
+ long nsec;
+ gettimeofday(&tv, NULL);
+ tv.tv_sec += millis / 1000;
+ millis %= 1000;
+ nsec = tv.tv_usec * 1000 + (s4) millis * 1000000 + nanos;
+ tm->tv_sec = tv.tv_sec + nsec / 1000000000;
+ tm->tv_nsec = nsec % 1000000000;
} else {
- releaseMetaLock(t, o, makeLockBits(lr, WAITERS));
+ tm->tv_sec = 0;
+ tm->tv_nsec = 0;
}
}
-void monitorWait(threadobject *t, java_objectheader *o, s8 millis)
-{
- long r = getMetaLock(t, o);
- monitorLockRecord *ownerLR = lockRecord(r);
- int state = lockState(r);
- if (state == LOCKED && ownerLR->owner == t) {
- pthread_mutex_lock(&t->ee.monitorLockMutex);
- t->ee.isWaitingForNotify = true;
- monitorExitSlow(t, o, ownerLR);
- if (millis == -1)
- pthread_cond_wait(&t->ee.monitorLockCond, &t->ee.monitorLockMutex);
- else
- timedCondWait(&t->ee.monitorLockCond, &t->ee.monitorLockMutex, millis);
- t->ee.isWaitingForNotify = false;
- pthread_mutex_unlock(&t->ee.monitorLockMutex);
- r = getMetaLock(t, o);
- monitorEnterSlow(t, o, r);
- } else {
- releaseMetaLock(t, o, r);
- panic("Illegal monitor exception");
- }
+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);
+
+ if (wasinterrupted)
+ *exceptionptr = new_exception(string_java_lang_InterruptedException);
}
static void notifyOneOrAll(threadobject *t, java_objectheader *o, bool one)
{
- long r = getMetaLock(t, o);
- monitorLockRecord *ownerLR = lockRecord(r);
- int state = lockState(r);
- if (state == LOCKED && ownerLR->owner == t) {
- monitorLockRecord *q = ownerLR->queue;
- while (q) {
- if (q->owner->ee.isWaitingForNotify) {
- q->owner->ee.isWaitingForNotify = false;
- if (one)
- break;
- }
- q = q->queue;
- }
- releaseMetaLock(t, o, r);
- } else {
- releaseMetaLock(t, o, r);
- panic("Illegal monitor exception");
- }
+ 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);
+}
+
+bool threadHoldsLock(threadobject *t, java_objectheader *o)
+{
+ monitorLockRecord *lr = o->monitorPtr;
+ GRAB_LR(lr, t);
+ return lr->o == o && lr->ownerThread == t;
+}
+
+void interruptThread(java_lang_VMThread *thread)
+{
+ threadobject *t = (threadobject*) thread;
+
+ t->interrupted = true;
+ pthread_mutex_lock(&t->waitLock);
+ if (t->isSleeping)
+ pthread_cond_signal(&t->waitCond);
+ pthread_mutex_unlock(&t->waitLock);
+}
+
+bool interruptedThread()
+{
+ threadobject *t = (threadobject*) THREADOBJECT;
+ bool intr = t->interrupted;
+ t->interrupted = false;
+ return intr;
+}
+
+bool isInterruptedThread(java_lang_VMThread *thread)
+{
+ threadobject *t = (threadobject*) thread;
+ return t->interrupted;
+}
+
+void sleepThread(s8 millis, s4 nanos)
+{
+ bool wasinterrupted;
+ threadobject *t = (threadobject*) THREADOBJECT;
+ monitorLockRecord *lr;
+ struct timespec wakeupTime;
+ calcAbsoluteTime(&wakeupTime, millis, nanos);
+
+ lr = allocLockRecordSimple(t);
+ wasinterrupted = waitWithTimeout(t, lr, &wakeupTime);
+ recycleLockRecord(t, lr);
+
+ if (wasinterrupted)
+ *exceptionptr = new_exception(string_java_lang_InterruptedException);
+}
+
+void yieldThread()
+{
+ sched_yield();
+}
+
+void setPriorityThread(thread *t, s4 priority)
+{
+ nativethread *info = &((threadobject*) t->vmThread)->info;
+ setPriority(info->tid, priority);
}
-void wait_cond_for_object(java_objectheader *o, s8 time)
+void wait_cond_for_object(java_objectheader *o, s8 time, s4 nanos)
{
threadobject *t = (threadobject*) THREADOBJECT;
- monitorWait(t, o, time);
+ monitorWait(t, o, time, nanos);
}
void signal_cond_for_object(java_objectheader *o)
notifyOneOrAll(t, o, false);
}
-#endif
-
/*
* These are local overrides for various environment variables in Emacs.