diff --git a/classpath/java/lang/Runtime.java b/classpath/java/lang/Runtime.java index 51f15006c7..efdedff039 100644 --- a/classpath/java/lang/Runtime.java +++ b/classpath/java/lang/Runtime.java @@ -59,6 +59,8 @@ public class Runtime { return new MyProcess(process[0], (int) process[1], (int) process[2], (int) process[3]); } + public native void addShutdownHook(Thread t); + private static native void exec(String[] command, long[] process); private static native int exitValue(long pid); diff --git a/classpath/java/lang/Thread.java b/classpath/java/lang/Thread.java index e284c00df3..2e494c850c 100644 --- a/classpath/java/lang/Thread.java +++ b/classpath/java/lang/Thread.java @@ -252,10 +252,14 @@ public class Thread implements Runnable { return daemon; } - public void setDaemon(boolean v) { - daemon = v; + public synchronized void setDaemon(boolean v) { + if (v != daemon) { + setDaemon(this, v); + } } + private static native void setDaemon(Thread t, boolean increment); + public static native void yield(); public synchronized void join() throws InterruptedException { diff --git a/src/builtin.cpp b/src/builtin.cpp index 3a126a0312..a045d8d451 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -726,6 +726,8 @@ extern "C" JNIEXPORT void JNICALL Avian_java_lang_Runtime_exit (Thread* t, object, uintptr_t* arguments) { + shutDown(t); + t->m->system->exit(*arguments); } @@ -745,6 +747,18 @@ Avian_java_lang_Runtime_totalMemory return 0; } +extern "C" JNIEXPORT void JNICALL +Avian_java_lang_Runtime_addShutdownHook +(Thread* t, object, uintptr_t* arguments) +{ + object hook = reinterpret_cast(arguments[1]); + PROTECT(t, hook); + + ACQUIRE(t, t->m->shutdownLock); + + t->m->shutdownHooks = makePair(t, hook, t->m->shutdownHooks); +} + extern "C" JNIEXPORT int64_t JNICALL Avian_java_lang_Throwable_trace (Thread* t, object, uintptr_t* arguments) @@ -840,16 +854,8 @@ extern "C" JNIEXPORT int64_t JNICALL Avian_java_lang_Thread_doStart (Thread* t, object, uintptr_t* arguments) { - object this_ = reinterpret_cast(*arguments); - - Thread* p = t->m->processor->makeThread(t->m, this_, t); - - if (t->m->system->success(t->m->system->start(&(p->runnable)))) { - return reinterpret_cast(p); - } else { - p->exit(); - return 0; - } + return reinterpret_cast + (startThread(t, reinterpret_cast(*arguments))); } extern "C" JNIEXPORT void JNICALL @@ -896,6 +902,27 @@ Avian_java_lang_Thread_enumerate return count; } +extern "C" JNIEXPORT void JNICALL +Avian_java_lang_Thread_setDaemon +(Thread* t, object, uintptr_t* arguments) +{ + object thread = reinterpret_cast(arguments[0]); + bool daemon = arguments[1] != 0; + + ACQUIRE_RAW(t, t->m->stateLock); + + threadDaemon(t, thread) = daemon; + + if (daemon) { + ++ t->m->daemonCount; + } else { + expect(t, t->m->daemonCount); + -- t->m->daemonCount; + } + + t->m->stateLock->notifyAll(t->systemThread); +} + extern "C" JNIEXPORT int64_t JNICALL Avian_avian_resource_Handler_00024ResourceInputStream_getContentLength (Thread* t, object, uintptr_t* arguments) diff --git a/src/jnienv.cpp b/src/jnienv.cpp index 5195057e4a..7e6316f025 100644 --- a/src/jnienv.cpp +++ b/src/jnienv.cpp @@ -25,37 +25,6 @@ const uintptr_t InterfaceMethodID const uintptr_t NonVirtualMethodID = (static_cast(1) << (BitsPerWord - 2)); -jint JNICALL -DestroyJavaVM(Machine* m) -{ - System* s = m->system; - Heap* h = m->heap; - Processor* p = m->processor; - Finder* f = m->finder; - Thread* t = m->rootThread; - - // wait for other threads to exit - { ACQUIRE(t, m->stateLock); - - while (m->liveCount > 1) { - t->m->stateLock->wait(t->systemThread, 0); - } - } - - int exitCode = (t->exception ? -1 : 0); - enter(t, Thread::ActiveState); - t->exit(); - - m->dispose(); - h->disposeFixies(); - p->dispose(); - h->dispose(); - f->dispose(); - s->dispose(); - - return exitCode; -} - jint JNICALL AttachCurrentThread(Machine* m, Thread** t, void*) { @@ -94,6 +63,30 @@ DetachCurrentThread(Machine* m) } } +jint JNICALL +DestroyJavaVM(Machine* m) +{ + Thread* t; AttachCurrentThread(m, &t, 0); + + // wait for other non-daemon threads to exit + { ACQUIRE(t, t->m->stateLock); + while (t->m->liveCount - t->m->daemonCount > 1) { + t->m->stateLock->wait(t->systemThread, 0); + } + } + + { ENTER(t, Thread::ActiveState); + + shutDown(t); + } + + int exitCode = (t->exception ? -1 : 0); + + t->exit(); + + return exitCode; +} + jint JNICALL GetEnv(Machine* m, Thread** t, jint version) { @@ -431,7 +424,7 @@ CallBooleanMethodV(Thread* t, jobject o, jmethodID m, va_list a) object method = getMethod(t, m); object r = t->m->processor->invokeList(t, method, *o, true, a); - return (t->exception ? false : (intValue(t, r) != 0)); + return (r ? (intValue(t, r) != 0) : false); } jboolean JNICALL @@ -454,7 +447,7 @@ CallByteMethodV(Thread* t, jobject o, jmethodID m, va_list a) object method = getMethod(t, m); object r = t->m->processor->invokeList(t, method, *o, true, a); - return (t->exception ? 0 : intValue(t, r)); + return (r ? intValue(t, r) : 0); } jbyte JNICALL @@ -477,7 +470,7 @@ CallCharMethodV(Thread* t, jobject o, jmethodID m, va_list a) object method = getMethod(t, m); object r = t->m->processor->invokeList(t, method, *o, true, a); - return (t->exception ? 0 : intValue(t, r)); + return (r ? intValue(t, r) : 0); } jchar JNICALL @@ -500,7 +493,7 @@ CallShortMethodV(Thread* t, jobject o, jmethodID m, va_list a) object method = getMethod(t, m); object r = t->m->processor->invokeList(t, method, *o, true, a); - return (t->exception ? 0 : intValue(t, r)); + return (r ? intValue(t, r) : 0); } jshort JNICALL @@ -523,7 +516,7 @@ CallIntMethodV(Thread* t, jobject o, jmethodID m, va_list a) object method = getMethod(t, m); object r = t->m->processor->invokeList(t, method, *o, true, a); - return (t->exception ? 0 : intValue(t, r)); + return (r ? intValue(t, r) : 0); } jint JNICALL @@ -546,7 +539,7 @@ CallLongMethodV(Thread* t, jobject o, jmethodID m, va_list a) object method = getMethod(t, m); object r = t->m->processor->invokeList(t, method, *o, true, a); - return (t->exception ? 0 : longValue(t, r)); + return (r ? longValue(t, r) : 0); } jlong JNICALL @@ -569,7 +562,7 @@ CallFloatMethodV(Thread* t, jobject o, jmethodID m, va_list a) object method = getMethod(t, m); object r = t->m->processor->invokeList(t, method, *o, true, a); - return (t->exception ? 0 : bitsToFloat(intValue(t, r))); + return (r ? bitsToFloat(intValue(t, r)) : 0); } jfloat JNICALL @@ -592,7 +585,7 @@ CallDoubleMethodV(Thread* t, jobject o, jmethodID m, va_list a) object method = getMethod(t, m); object r = t->m->processor->invokeList(t, method, *o, true, a); - return (t->exception ? 0 : bitsToDouble(longValue(t, r))); + return (r ? bitsToDouble(longValue(t, r)) : 0); } jdouble JNICALL @@ -666,7 +659,7 @@ CallStaticBooleanMethodV(Thread* t, jclass, jmethodID m, va_list a) ENTER(t, Thread::ActiveState); object r = t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, a); - return (t->exception ? 0 : (intValue(t, r) != 0)); + return (r ? (intValue(t, r) != 0) : false); } jboolean JNICALL @@ -688,7 +681,7 @@ CallStaticByteMethodV(Thread* t, jclass, jmethodID m, va_list a) ENTER(t, Thread::ActiveState); object r = t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, a); - return (t->exception ? 0 : intValue(t, r)); + return (r ? intValue(t, r) : 0); } jbyte JNICALL @@ -710,7 +703,7 @@ CallStaticCharMethodV(Thread* t, jclass, jmethodID m, va_list a) ENTER(t, Thread::ActiveState); object r = t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, a); - return (t->exception ? 0 : intValue(t, r)); + return (r ? intValue(t, r) : 0); } jchar JNICALL @@ -732,7 +725,7 @@ CallStaticShortMethodV(Thread* t, jclass, jmethodID m, va_list a) ENTER(t, Thread::ActiveState); object r = t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, a); - return (t->exception ? 0 : intValue(t, r)); + return (r ? intValue(t, r) : 0); } jshort JNICALL @@ -754,7 +747,7 @@ CallStaticIntMethodV(Thread* t, jclass, jmethodID m, va_list a) ENTER(t, Thread::ActiveState); object r = t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, a); - return (t->exception ? 0 : intValue(t, r)); + return (r ? intValue(t, r) : 0); } jint JNICALL @@ -776,7 +769,7 @@ CallStaticLongMethodV(Thread* t, jclass, jmethodID m, va_list a) ENTER(t, Thread::ActiveState); object r = t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, a); - return (t->exception ? 0 : longValue(t, r)); + return (r ? longValue(t, r) : 0); } jlong JNICALL @@ -798,7 +791,7 @@ CallStaticFloatMethodV(Thread* t, jclass, jmethodID m, va_list a) ENTER(t, Thread::ActiveState); object r = t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, a); - return (t->exception ? 0 : bitsToFloat(intValue(t, r))); + return (r ? bitsToFloat(intValue(t, r)) : 0); } jfloat JNICALL @@ -820,7 +813,7 @@ CallStaticDoubleMethodV(Thread* t, jclass, jmethodID m, va_list a) ENTER(t, Thread::ActiveState); object r = t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, a); - return (t->exception ? 0 : bitsToDouble(longValue(t, r))); + return (r ? bitsToDouble(longValue(t, r)) : 0); } jdouble JNICALL diff --git a/src/machine.cpp b/src/machine.cpp index 1fa9791397..6e046843d0 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -146,6 +146,50 @@ disposeAll(Thread* m, Thread* o) dispose(m, o, false); } +void +turnOffTheLights(Thread* t) +{ + expect(t, t->m->liveCount == 1); + + joinAll(t, t->m->rootThread); + + enter(t, Thread::ExitState); + + for (object* p = &(t->m->finalizers); *p;) { + object f = *p; + *p = finalizerNext(t, *p); + + void (*function)(Thread*, object); + memcpy(&function, &finalizerFinalize(t, f), BytesPerWord); + function(t, finalizerTarget(t, f)); + } + + for (object* p = &(t->m->tenuredFinalizers); *p;) { + object f = *p; + *p = finalizerNext(t, *p); + + void (*function)(Thread*, object); + memcpy(&function, &finalizerFinalize(t, f), BytesPerWord); + function(t, finalizerTarget(t, f)); + } + + Machine* m = t->m; + + disposeAll(t, t->m->rootThread); + + System* s = m->system; + Heap* h = m->heap; + Processor* p = m->processor; + Finder* f = m->finder; + + m->dispose(); + h->disposeFixies(); + p->dispose(); + h->dispose(); + f->dispose(); + s->dispose(); +} + void killZombies(Thread* t, Thread* o) { @@ -1976,12 +2020,14 @@ Machine::Machine(System* system, Heap* heap, Finder* finder, propertyCount(propertyCount), activeCount(0), liveCount(0), + daemonCount(0), fixedFootprint(0), localThread(0), stateLock(0), heapLock(0), classLock(0), referenceLock(0), + shutdownLock(0), libraries(0), loader(0), loadClassMethod(0), @@ -1996,6 +2042,7 @@ Machine::Machine(System* system, Heap* heap, Finder* finder, finalizeQueue(0), weakReferences(0), tenuredWeakReferences(0), + shutdownHooks(0), unsafe(false), triedBuiltinOnLoad(false), heapPoolIndex(0) @@ -2009,6 +2056,7 @@ Machine::Machine(System* system, Heap* heap, Finder* finder, not system->success(system->make(&heapLock)) or not system->success(system->make(&classLock)) or not system->success(system->make(&referenceLock)) or + not system->success(system->make(&shutdownLock)) or not system->success (system->load(&libraries, findProperty(this, "avian.bootstrap"), false))) { @@ -2024,6 +2072,7 @@ Machine::dispose() heapLock->dispose(); classLock->dispose(); referenceLock->dispose(); + shutdownLock->dispose(); if (libraries) { libraries->disposeAll(); @@ -2150,7 +2199,7 @@ Thread::exit() enter(this, Thread::ExclusiveState); if (m->liveCount == 1) { - vm::exit(this); + turnOffTheLights(this); } else { enter(this, Thread::ZombieState); } @@ -2160,6 +2209,8 @@ Thread::exit() void Thread::dispose() { + threadPeer(this, javaThread) = 0; + if (systemThread) { systemThread->dispose(); } @@ -2170,31 +2221,41 @@ Thread::dispose() } void -exit(Thread* t) +shutDown(Thread* t) { - enter(t, Thread::ExitState); + ACQUIRE(t, t->m->shutdownLock); - joinAll(t, t->m->rootThread); + object hooks = t->m->shutdownHooks; + PROTECT(t, hooks); - for (object* p = &(t->m->finalizers); *p;) { - object f = *p; - *p = finalizerNext(t, *p); + t->m->shutdownHooks = 0; - void (*function)(Thread*, object); - memcpy(&function, &finalizerFinalize(t, f), BytesPerWord); - function(t, finalizerTarget(t, f)); + object h = hooks; + PROTECT(t, h); + for (; h; h = pairSecond(t, h)) { + startThread(t, pairFirst(t, h)); } - for (object* p = &(t->m->tenuredFinalizers); *p;) { - object f = *p; - *p = finalizerNext(t, *p); + // wait for hooks to exit + h = hooks; + for (; h; h = pairSecond(t, h)) { + while (true) { + Thread* ht = reinterpret_cast(threadPeer(t, pairFirst(t, h))); - void (*function)(Thread*, object); - memcpy(&function, &finalizerFinalize(t, f), BytesPerWord); - function(t, finalizerTarget(t, f)); + { ACQUIRE(t, t->m->stateLock); + + if (ht == 0 + or ht->state == Thread::ZombieState + or ht->state == Thread::JoinedState) + { + break; + } else { + ENTER(t, Thread::IdleState); + t->m->stateLock->wait(t->systemThread, 0); + } + } + } } - - disposeAll(t, t->m->rootThread); } void @@ -2255,6 +2316,10 @@ enter(Thread* t, Thread::State s) if (s == Thread::ZombieState) { assert(t, t->m->liveCount > 0); -- t->m->liveCount; + + if (threadDaemon(t, t->javaThread)) { + -- t->m->daemonCount; + } } t->state = s; @@ -2308,7 +2373,7 @@ enter(Thread* t, Thread::State s) t->state = s; - while (t->m->liveCount > 1) { + while (t->m->liveCount - t->m->daemonCount > 1) { t->m->stateLock->wait(t->systemThread, 0); } } break; @@ -3436,6 +3501,7 @@ visitRoots(Machine* m, Heap::Visitor* v) v->visit(&(m->byteArrayMap)); v->visit(&(m->types)); v->visit(&(m->jniMethodTable)); + v->visit(&(m->shutdownHooks)); for (Thread* t = m->rootThread; t; t = t->peer) { ::visitRoots(t, v); diff --git a/src/machine.h b/src/machine.h index 1539b80af0..078355dbe9 100644 --- a/src/machine.h +++ b/src/machine.h @@ -1178,12 +1178,14 @@ class Machine { unsigned propertyCount; unsigned activeCount; unsigned liveCount; + unsigned daemonCount; unsigned fixedFootprint; System::Local* localThread; System::Monitor* stateLock; System::Monitor* heapLock; System::Monitor* classLock; System::Monitor* referenceLock; + System::Monitor* shutdownLock; System::Library* libraries; object loader; object loadClassMethod; @@ -1198,6 +1200,7 @@ class Machine { object finalizeQueue; object weakReferences; object tenuredWeakReferences; + object shutdownHooks; bool unsafe; bool triedBuiltinOnLoad; JavaVMVTable javaVMVTable; @@ -1394,6 +1397,9 @@ dispose(Thread* t, Reference* r) void collect(Thread* t, Heap::CollectionType type); +void +shutDown(Thread* t); + #ifdef VM_STRESS inline void @@ -1599,6 +1605,19 @@ setObjectClass(Thread*, object o, object value) | (reinterpret_cast(cast(o, 0)) & (~PointerMask))); } +inline Thread* +startThread(Thread* t, object javaThread) +{ + Thread* p = t->m->processor->makeThread(t->m, javaThread, t); + + if (t->m->system->success(t->m->system->start(&(p->runnable)))) { + return p; + } else { + p->exit(); + return 0; + } +} + inline const char* findProperty(Machine* m, const char* name) { @@ -2341,9 +2360,6 @@ interrupt(Thread*, Thread* target) object intern(Thread* t, object s); -void -exit(Thread* t); - void walk(Thread* t, Heap::Walker* w, object o, unsigned start);