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]);
}
public native void addShutdownHook(Thread t);
private static native void exec(String[] command, long[] process);
private static native int exitValue(long pid);

View File

@ -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 {

View File

@ -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<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
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<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;
}
return reinterpret_cast<int64_t>
(startThread(t, reinterpret_cast<object>(*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<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
Avian_avian_resource_Handler_00024ResourceInputStream_getContentLength
(Thread* t, object, uintptr_t* arguments)

View File

@ -25,37 +25,6 @@ const uintptr_t InterfaceMethodID
const uintptr_t NonVirtualMethodID
= (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
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

View File

@ -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<Thread*>(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);

View File

@ -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<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*
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);