implement Runtime.addShutdownHook and Thread.setDaemon; avoid segfaults due to an application calling e.g. CallStaticBooleanMethod when it really meant CallStaticVoidMethod

This commit is contained in:
Joel Dice 2009-08-19 14:27:03 -06:00
parent df3baeb83b
commit c4b5ecec90
6 changed files with 189 additions and 81 deletions

View File

@ -59,6 +59,8 @@ public class Runtime {
return new MyProcess(process[0], (int) process[1], (int) process[2], (int) process[3]); 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 void exec(String[] command, long[] process);
private static native int exitValue(long pid); private static native int exitValue(long pid);

View File

@ -252,10 +252,14 @@ public class Thread implements Runnable {
return daemon; return daemon;
} }
public void setDaemon(boolean v) { public synchronized void setDaemon(boolean v) {
daemon = v; if (v != daemon) {
setDaemon(this, v);
}
} }
private static native void setDaemon(Thread t, boolean increment);
public static native void yield(); public static native void yield();
public synchronized void join() throws InterruptedException { public synchronized void join() throws InterruptedException {

View File

@ -726,6 +726,8 @@ extern "C" JNIEXPORT void JNICALL
Avian_java_lang_Runtime_exit Avian_java_lang_Runtime_exit
(Thread* t, object, uintptr_t* arguments) (Thread* t, object, uintptr_t* arguments)
{ {
shutDown(t);
t->m->system->exit(*arguments); t->m->system->exit(*arguments);
} }
@ -745,6 +747,18 @@ Avian_java_lang_Runtime_totalMemory
return 0; return 0;
} }
extern "C" JNIEXPORT void JNICALL
Avian_java_lang_Runtime_addShutdownHook
(Thread* t, object, uintptr_t* arguments)
{
object hook = reinterpret_cast<object>(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 extern "C" JNIEXPORT int64_t JNICALL
Avian_java_lang_Throwable_trace Avian_java_lang_Throwable_trace
(Thread* t, object, uintptr_t* arguments) (Thread* t, object, uintptr_t* arguments)
@ -840,16 +854,8 @@ extern "C" JNIEXPORT int64_t JNICALL
Avian_java_lang_Thread_doStart Avian_java_lang_Thread_doStart
(Thread* t, object, uintptr_t* arguments) (Thread* t, object, uintptr_t* arguments)
{ {
object this_ = reinterpret_cast<object>(*arguments); return reinterpret_cast<int64_t>
(startThread(t, reinterpret_cast<object>(*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<int64_t>(p);
} else {
p->exit();
return 0;
}
} }
extern "C" JNIEXPORT void JNICALL extern "C" JNIEXPORT void JNICALL
@ -896,6 +902,27 @@ Avian_java_lang_Thread_enumerate
return count; return count;
} }
extern "C" JNIEXPORT void JNICALL
Avian_java_lang_Thread_setDaemon
(Thread* t, object, uintptr_t* arguments)
{
object thread = reinterpret_cast<object>(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 extern "C" JNIEXPORT int64_t JNICALL
Avian_avian_resource_Handler_00024ResourceInputStream_getContentLength Avian_avian_resource_Handler_00024ResourceInputStream_getContentLength
(Thread* t, object, uintptr_t* arguments) (Thread* t, object, uintptr_t* arguments)

View File

@ -25,37 +25,6 @@ const uintptr_t InterfaceMethodID
const uintptr_t NonVirtualMethodID const uintptr_t NonVirtualMethodID
= (static_cast<uintptr_t>(1) << (BitsPerWord - 2)); = (static_cast<uintptr_t>(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 jint JNICALL
AttachCurrentThread(Machine* m, Thread** t, void*) 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 jint JNICALL
GetEnv(Machine* m, Thread** t, jint version) 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 method = getMethod(t, m);
object r = t->m->processor->invokeList(t, method, *o, true, a); 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 jboolean JNICALL
@ -454,7 +447,7 @@ CallByteMethodV(Thread* t, jobject o, jmethodID m, va_list a)
object method = getMethod(t, m); object method = getMethod(t, m);
object r = t->m->processor->invokeList(t, method, *o, true, a); 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 jbyte JNICALL
@ -477,7 +470,7 @@ CallCharMethodV(Thread* t, jobject o, jmethodID m, va_list a)
object method = getMethod(t, m); object method = getMethod(t, m);
object r = t->m->processor->invokeList(t, method, *o, true, a); 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 jchar JNICALL
@ -500,7 +493,7 @@ CallShortMethodV(Thread* t, jobject o, jmethodID m, va_list a)
object method = getMethod(t, m); object method = getMethod(t, m);
object r = t->m->processor->invokeList(t, method, *o, true, a); 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 jshort JNICALL
@ -523,7 +516,7 @@ CallIntMethodV(Thread* t, jobject o, jmethodID m, va_list a)
object method = getMethod(t, m); object method = getMethod(t, m);
object r = t->m->processor->invokeList(t, method, *o, true, a); 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 jint JNICALL
@ -546,7 +539,7 @@ CallLongMethodV(Thread* t, jobject o, jmethodID m, va_list a)
object method = getMethod(t, m); object method = getMethod(t, m);
object r = t->m->processor->invokeList(t, method, *o, true, a); 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 jlong JNICALL
@ -569,7 +562,7 @@ CallFloatMethodV(Thread* t, jobject o, jmethodID m, va_list a)
object method = getMethod(t, m); object method = getMethod(t, m);
object r = t->m->processor->invokeList(t, method, *o, true, a); 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 jfloat JNICALL
@ -592,7 +585,7 @@ CallDoubleMethodV(Thread* t, jobject o, jmethodID m, va_list a)
object method = getMethod(t, m); object method = getMethod(t, m);
object r = t->m->processor->invokeList(t, method, *o, true, a); 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 jdouble JNICALL
@ -666,7 +659,7 @@ CallStaticBooleanMethodV(Thread* t, jclass, jmethodID m, va_list a)
ENTER(t, Thread::ActiveState); ENTER(t, Thread::ActiveState);
object r = t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, a); 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 jboolean JNICALL
@ -688,7 +681,7 @@ CallStaticByteMethodV(Thread* t, jclass, jmethodID m, va_list a)
ENTER(t, Thread::ActiveState); ENTER(t, Thread::ActiveState);
object r = t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, a); 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 jbyte JNICALL
@ -710,7 +703,7 @@ CallStaticCharMethodV(Thread* t, jclass, jmethodID m, va_list a)
ENTER(t, Thread::ActiveState); ENTER(t, Thread::ActiveState);
object r = t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, a); 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 jchar JNICALL
@ -732,7 +725,7 @@ CallStaticShortMethodV(Thread* t, jclass, jmethodID m, va_list a)
ENTER(t, Thread::ActiveState); ENTER(t, Thread::ActiveState);
object r = t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, a); 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 jshort JNICALL
@ -754,7 +747,7 @@ CallStaticIntMethodV(Thread* t, jclass, jmethodID m, va_list a)
ENTER(t, Thread::ActiveState); ENTER(t, Thread::ActiveState);
object r = t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, a); 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 jint JNICALL
@ -776,7 +769,7 @@ CallStaticLongMethodV(Thread* t, jclass, jmethodID m, va_list a)
ENTER(t, Thread::ActiveState); ENTER(t, Thread::ActiveState);
object r = t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, a); 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 jlong JNICALL
@ -798,7 +791,7 @@ CallStaticFloatMethodV(Thread* t, jclass, jmethodID m, va_list a)
ENTER(t, Thread::ActiveState); ENTER(t, Thread::ActiveState);
object r = t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, a); 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 jfloat JNICALL
@ -820,7 +813,7 @@ CallStaticDoubleMethodV(Thread* t, jclass, jmethodID m, va_list a)
ENTER(t, Thread::ActiveState); ENTER(t, Thread::ActiveState);
object r = t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, a); 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 jdouble JNICALL

View File

@ -146,6 +146,50 @@ disposeAll(Thread* m, Thread* o)
dispose(m, o, false); 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 void
killZombies(Thread* t, Thread* o) killZombies(Thread* t, Thread* o)
{ {
@ -1976,12 +2020,14 @@ Machine::Machine(System* system, Heap* heap, Finder* finder,
propertyCount(propertyCount), propertyCount(propertyCount),
activeCount(0), activeCount(0),
liveCount(0), liveCount(0),
daemonCount(0),
fixedFootprint(0), fixedFootprint(0),
localThread(0), localThread(0),
stateLock(0), stateLock(0),
heapLock(0), heapLock(0),
classLock(0), classLock(0),
referenceLock(0), referenceLock(0),
shutdownLock(0),
libraries(0), libraries(0),
loader(0), loader(0),
loadClassMethod(0), loadClassMethod(0),
@ -1996,6 +2042,7 @@ Machine::Machine(System* system, Heap* heap, Finder* finder,
finalizeQueue(0), finalizeQueue(0),
weakReferences(0), weakReferences(0),
tenuredWeakReferences(0), tenuredWeakReferences(0),
shutdownHooks(0),
unsafe(false), unsafe(false),
triedBuiltinOnLoad(false), triedBuiltinOnLoad(false),
heapPoolIndex(0) 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(&heapLock)) or
not system->success(system->make(&classLock)) or not system->success(system->make(&classLock)) or
not system->success(system->make(&referenceLock)) or not system->success(system->make(&referenceLock)) or
not system->success(system->make(&shutdownLock)) or
not system->success not system->success
(system->load(&libraries, findProperty(this, "avian.bootstrap"), false))) (system->load(&libraries, findProperty(this, "avian.bootstrap"), false)))
{ {
@ -2024,6 +2072,7 @@ Machine::dispose()
heapLock->dispose(); heapLock->dispose();
classLock->dispose(); classLock->dispose();
referenceLock->dispose(); referenceLock->dispose();
shutdownLock->dispose();
if (libraries) { if (libraries) {
libraries->disposeAll(); libraries->disposeAll();
@ -2150,7 +2199,7 @@ Thread::exit()
enter(this, Thread::ExclusiveState); enter(this, Thread::ExclusiveState);
if (m->liveCount == 1) { if (m->liveCount == 1) {
vm::exit(this); turnOffTheLights(this);
} else { } else {
enter(this, Thread::ZombieState); enter(this, Thread::ZombieState);
} }
@ -2160,6 +2209,8 @@ Thread::exit()
void void
Thread::dispose() Thread::dispose()
{ {
threadPeer(this, javaThread) = 0;
if (systemThread) { if (systemThread) {
systemThread->dispose(); systemThread->dispose();
} }
@ -2170,31 +2221,41 @@ Thread::dispose()
} }
void 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;) { t->m->shutdownHooks = 0;
object f = *p;
*p = finalizerNext(t, *p);
void (*function)(Thread*, object); object h = hooks;
memcpy(&function, &finalizerFinalize(t, f), BytesPerWord); PROTECT(t, h);
function(t, finalizerTarget(t, f)); for (; h; h = pairSecond(t, h)) {
startThread(t, pairFirst(t, h));
} }
for (object* p = &(t->m->tenuredFinalizers); *p;) { // wait for hooks to exit
object f = *p; h = hooks;
*p = finalizerNext(t, *p); for (; h; h = pairSecond(t, h)) {
while (true) {
Thread* ht = reinterpret_cast<Thread*>(threadPeer(t, pairFirst(t, h)));
void (*function)(Thread*, object); { ACQUIRE(t, t->m->stateLock);
memcpy(&function, &finalizerFinalize(t, f), BytesPerWord);
function(t, finalizerTarget(t, f)); 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 void
@ -2255,6 +2316,10 @@ enter(Thread* t, Thread::State s)
if (s == Thread::ZombieState) { if (s == Thread::ZombieState) {
assert(t, t->m->liveCount > 0); assert(t, t->m->liveCount > 0);
-- t->m->liveCount; -- t->m->liveCount;
if (threadDaemon(t, t->javaThread)) {
-- t->m->daemonCount;
}
} }
t->state = s; t->state = s;
@ -2308,7 +2373,7 @@ enter(Thread* t, Thread::State s)
t->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); t->m->stateLock->wait(t->systemThread, 0);
} }
} break; } break;
@ -3436,6 +3501,7 @@ visitRoots(Machine* m, Heap::Visitor* v)
v->visit(&(m->byteArrayMap)); v->visit(&(m->byteArrayMap));
v->visit(&(m->types)); v->visit(&(m->types));
v->visit(&(m->jniMethodTable)); v->visit(&(m->jniMethodTable));
v->visit(&(m->shutdownHooks));
for (Thread* t = m->rootThread; t; t = t->peer) { for (Thread* t = m->rootThread; t; t = t->peer) {
::visitRoots(t, v); ::visitRoots(t, v);

View File

@ -1178,12 +1178,14 @@ class Machine {
unsigned propertyCount; unsigned propertyCount;
unsigned activeCount; unsigned activeCount;
unsigned liveCount; unsigned liveCount;
unsigned daemonCount;
unsigned fixedFootprint; unsigned fixedFootprint;
System::Local* localThread; System::Local* localThread;
System::Monitor* stateLock; System::Monitor* stateLock;
System::Monitor* heapLock; System::Monitor* heapLock;
System::Monitor* classLock; System::Monitor* classLock;
System::Monitor* referenceLock; System::Monitor* referenceLock;
System::Monitor* shutdownLock;
System::Library* libraries; System::Library* libraries;
object loader; object loader;
object loadClassMethod; object loadClassMethod;
@ -1198,6 +1200,7 @@ class Machine {
object finalizeQueue; object finalizeQueue;
object weakReferences; object weakReferences;
object tenuredWeakReferences; object tenuredWeakReferences;
object shutdownHooks;
bool unsafe; bool unsafe;
bool triedBuiltinOnLoad; bool triedBuiltinOnLoad;
JavaVMVTable javaVMVTable; JavaVMVTable javaVMVTable;
@ -1394,6 +1397,9 @@ dispose(Thread* t, Reference* r)
void void
collect(Thread* t, Heap::CollectionType type); collect(Thread* t, Heap::CollectionType type);
void
shutDown(Thread* t);
#ifdef VM_STRESS #ifdef VM_STRESS
inline void inline void
@ -1599,6 +1605,19 @@ setObjectClass(Thread*, object o, object value)
| (reinterpret_cast<uintptr_t>(cast<object>(o, 0)) & (~PointerMask))); | (reinterpret_cast<uintptr_t>(cast<object>(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* inline const char*
findProperty(Machine* m, const char* name) findProperty(Machine* m, const char* name)
{ {
@ -2341,9 +2360,6 @@ interrupt(Thread*, Thread* target)
object object
intern(Thread* t, object s); intern(Thread* t, object s);
void
exit(Thread* t);
void void
walk(Thread* t, Heap::Walker* w, object o, unsigned start); walk(Thread* t, Heap::Walker* w, object o, unsigned start);