-#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 "exceptions.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>
#elif defined(__MIPS__)
#define GC_IRIX_THREADS
#endif
-#include "../mm/boehm-gc/include/gc.h"
+#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;
#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;
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");
/* Do as Boehm does. On IRIX a condition variable is used for wake-up
(not POSIX async-safe). */
-#if defined(__MIPS__)
+#if defined(__IRIX__)
pthread_mutex_lock(&suspend_ack_lock);
sem_post(&suspend_ack);
pthread_cond_wait(&suspend_cond, &suspend_ack_lock);
#endif
}
+static monitorLockRecord *dummyLR;
+
+static void initPools();
+
/*
* Initialize threads.
*/
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
{
classinfo *threadclass;
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);
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);
if (!mainthreadobj)
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"));
- mainthread->group =
+ threadgroup =
(java_lang_ThreadGroup *) native_new_and_init(threadgroupclass);
- if (!mainthread->group)
+ 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 *);
startup = NULL;
sem_post(psem);
+ setPriority(info->tid, thread->o.thread->priority);
+ sched_yield();
+
/* Find the run()V method and call it */
method = class_resolveclassmethod(thread->o.header.vftbl->class,
utf_new_char("run"),
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, s4 nanos)
-{
- struct timespec tv;
- tv.tv_sec = millis / 1000;
- tv.tv_nsec = millis % 1000 * 1000000 + nanos;
- 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);
-}
-
-static inline long makeLockBits(void *r, long l)
-{
- return ((long) r) | l;
+ thread->ee.firstLR = NULL;
+ thread->ee.lrpool = NULL;
+ thread->ee.numlr = 0;
}
-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);
+ 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);
+}
- 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);
- }
+bool waitWithTimeout(threadobject *t, monitorLockRecord *lr, struct timespec *wakeupTime)
+{
+ 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 calcAbsoluteTime(struct timespec *tm, s8 millis, s4 nanos)
+{
+ 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, r);
-
- /* throw an exception */
-
- *exceptionptr =
- new_exception(string_java_lang_IllegalMonitorStateException);
+ tm->tv_sec = 0;
+ tm->tv_nsec = 0;
}
}
-static threadobject *wakeupEE(monitorLockRecord *lr)
+void monitorWait(threadobject *t, java_objectheader *o, s8 millis, s4 nanos)
{
- while (lr->queue && lr->queue->owner->ee.isWaitingForNotify)
- lr = lr->queue;
- return lr->owner;
+ 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 monitorExitSlow(threadobject *t, java_objectheader *o, monitorLockRecord *lr)
+static void notifyOneOrAll(threadobject *t, java_objectheader *o, bool one)
{
- 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);
- } else {
- releaseMetaLock(t, o, makeLockBits(lr, WAITERS));
- }
+ 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);
}
-void monitorWait(threadobject *t, java_objectheader *o, s8 millis)
+bool threadHoldsLock(threadobject *t, java_objectheader *o)
{
- long r = getMetaLock(t, o);
- monitorLockRecord *ownerLR = lockRecord(r);
- int state = lockState(r);
+ monitorLockRecord *lr = o->monitorPtr;
+ GRAB_LR(lr, t);
+ return lr->o == o && lr->ownerThread == t;
+}
- 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);
+void interruptThread(java_lang_VMThread *thread)
+{
+ threadobject *t = (threadobject*) thread;
- } else {
- releaseMetaLock(t, o, r);
+ t->interrupted = true;
+ pthread_mutex_lock(&t->waitLock);
+ if (t->isSleeping)
+ pthread_cond_signal(&t->waitCond);
+ pthread_mutex_unlock(&t->waitLock);
+}
- /* throw an exception */
+bool interruptedThread()
+{
+ threadobject *t = (threadobject*) THREADOBJECT;
+ bool intr = t->interrupted;
+ t->interrupted = false;
+ return intr;
+}
- *exceptionptr =
- new_exception(string_java_lang_IllegalMonitorStateException);
- }
+bool isInterruptedThread(java_lang_VMThread *thread)
+{
+ threadobject *t = (threadobject*) thread;
+ return t->interrupted;
}
-static void notifyOneOrAll(threadobject *t, java_objectheader *o, bool one)
+void sleepThread(s8 millis, s4 nanos)
{
- 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);
+ bool wasinterrupted;
+ threadobject *t = (threadobject*) THREADOBJECT;
+ monitorLockRecord *lr;
+ struct timespec wakeupTime;
+ calcAbsoluteTime(&wakeupTime, millis, nanos);
- } else {
- releaseMetaLock(t, o, r);
+ lr = allocLockRecordSimple(t);
+ wasinterrupted = waitWithTimeout(t, lr, &wakeupTime);
+ recycleLockRecord(t, lr);
- /* throw an exception */
+ if (wasinterrupted)
+ *exceptionptr = new_exception(string_java_lang_InterruptedException);
+}
- *exceptionptr =
- new_exception(string_java_lang_IllegalMonitorStateException);
- }
+void yieldThread()
+{
+ sched_yield();
}
-void wait_cond_for_object(java_objectheader *o, s8 time)
+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, 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.