run java finalizers in a separate thread to guarantee no application locks are held when doing so

This commit is contained in:
Joel Dice 2009-08-24 17:51:31 -06:00
parent d4e2e05b31
commit 4297fa04b3
4 changed files with 135 additions and 43 deletions

View File

@ -909,18 +909,7 @@ Avian_java_lang_Thread_setDaemon
object thread = reinterpret_cast<object>(arguments[0]); object thread = reinterpret_cast<object>(arguments[0]);
bool daemon = arguments[1] != 0; bool daemon = arguments[1] != 0;
ACQUIRE_RAW(t, t->m->stateLock); setDaemon(t, thread, daemon);
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

View File

@ -211,6 +211,23 @@ killZombies(Thread* t, Thread* o)
} }
} }
object
makeJavaThread(Thread* t, Thread* parent)
{
object group;
if (parent) {
group = threadGroup(t, parent->javaThread);
} else {
group = makeThreadGroup(t, 0, 0);
}
const unsigned NewState = 0;
const unsigned NormalPriority = 5;
return makeThread
(t, 0, 0, 0, NewState, NormalPriority, 0, 0, 0, t->m->loader, 0, 0, group);
}
unsigned unsigned
footprint(Thread* t) footprint(Thread* t)
{ {
@ -547,12 +564,6 @@ postCollect(Thread* t)
void void
finalizeObject(Thread* t, object o) finalizeObject(Thread* t, object o)
{ {
if (t->state == Thread::ExitState) {
// don't waste time running Java finalizers if we're exiting the
// VM
return;
}
for (object c = objectClass(t, o); c; c = classSuper(t, c)) { for (object c = objectClass(t, o); c; c = classSuper(t, c)) {
for (unsigned i = 0; i < arrayLength(t, classMethodTable(t, c)); ++i) { for (unsigned i = 0; i < arrayLength(t, classMethodTable(t, c)); ++i) {
object m = arrayBody(t, classMethodTable(t, c), i); object m = arrayBody(t, classMethodTable(t, c), i);
@ -2016,6 +2027,7 @@ Machine::Machine(System* system, Heap* heap, Finder* finder,
processor(processor), processor(processor),
rootThread(0), rootThread(0),
exclusive(0), exclusive(0),
finalizeThread(0),
jniReferences(0), jniReferences(0),
properties(properties), properties(properties),
propertyCount(propertyCount), propertyCount(propertyCount),
@ -2044,6 +2056,7 @@ Machine::Machine(System* system, Heap* heap, Finder* finder,
weakReferences(0), weakReferences(0),
tenuredWeakReferences(0), tenuredWeakReferences(0),
shutdownHooks(0), shutdownHooks(0),
objectsToFinalize(0),
unsafe(false), unsafe(false),
triedBuiltinOnLoad(false), triedBuiltinOnLoad(false),
heapPoolIndex(0) heapPoolIndex(0)
@ -2172,23 +2185,11 @@ Thread::init()
parent->child = this; parent->child = this;
} }
if (javaThread) { if (javaThread == 0) {
this->javaThread = makeJavaThread(this, parent);
}
threadPeer(this, javaThread) = reinterpret_cast<jlong>(this); threadPeer(this, javaThread) = reinterpret_cast<jlong>(this);
} else {
object group;
if (parent) {
group = threadGroup(this, parent->javaThread);
} else {
group = makeThreadGroup(this, 0, 0);
}
const unsigned NewState = 0;
const unsigned NormalPriority = 5;
this->javaThread = makeThread
(this, reinterpret_cast<int64_t>(this), 0, 0, NewState, NormalPriority,
0, 0, 0, m->loader, 0, 0, group);
}
} }
void void
@ -2256,6 +2257,22 @@ shutDown(Thread* t)
} }
} }
} }
// tell finalize thread to exit and wait for it to do so
{ ACQUIRE(t, t->m->stateLock);
Thread* finalizeThread = t->m->finalizeThread;
if (finalizeThread) {
t->m->finalizeThread = 0;
t->m->stateLock->notifyAll(t->systemThread);
while (finalizeThread->state != Thread::ZombieState
and finalizeThread->state != Thread::JoinedState)
{
ENTER(t, Thread::IdleState);
t->m->stateLock->wait(t->systemThread, 0);
}
}
}
} }
void void
@ -2519,7 +2536,7 @@ makeNewGeneral(Thread* t, object class_)
} }
if (classVmFlags(t, class_) & HasFinalizerFlag) { if (classVmFlags(t, class_) & HasFinalizerFlag) {
addFinalizer(t, instance, finalizeObject); addFinalizer(t, instance, 0);
} }
return instance; return instance;
@ -3429,7 +3446,24 @@ collect(Thread* t, Heap::CollectionType type)
for (; f; f = finalizerNext(t, f)) { for (; f; f = finalizerNext(t, f)) {
void (*function)(Thread*, object); void (*function)(Thread*, object);
memcpy(&function, &finalizerFinalize(t, f), BytesPerWord); memcpy(&function, &finalizerFinalize(t, f), BytesPerWord);
if (function) {
function(t, finalizerTarget(t, f)); function(t, finalizerTarget(t, f));
} else {
m->objectsToFinalize = makePair
(t, finalizerTarget(t, f), m->objectsToFinalize);
}
}
if (m->objectsToFinalize and m->finalizeThread == 0) {
m->finalizeThread = m->processor->makeThread
(m, makeJavaThread(t, m->rootThread), m->rootThread);
if (not t->m->system->success
(m->system->start(&(m->finalizeThread->runnable))))
{
m->finalizeThread->exit();
m->finalizeThread = 0;
}
} }
} }
@ -3502,6 +3536,7 @@ visitRoots(Machine* m, Heap::Visitor* v)
v->visit(&(m->types)); v->visit(&(m->types));
v->visit(&(m->jniMethodTable)); v->visit(&(m->jniMethodTable));
v->visit(&(m->shutdownHooks)); v->visit(&(m->shutdownHooks));
v->visit(&(m->objectsToFinalize));
for (Thread* t = m->rootThread; t; t = t->peer) { for (Thread* t = m->rootThread; t; t = t->peer) {
::visitRoots(t, v); ::visitRoots(t, v);
@ -3624,6 +3659,36 @@ runJavaThread(Thread* t)
} }
} }
void
runFinalizeThread(Thread* t)
{
setDaemon(t, t->javaThread, true);
object list = 0;
PROTECT(t, list);
while (true) {
{ ACQUIRE(t, t->m->stateLock);
while (t->m->finalizeThread and t->m->objectsToFinalize == 0) {
ENTER(t, Thread::IdleState);
t->m->stateLock->wait(t->systemThread, 0);
}
if (t->m->finalizeThread == 0) {
return;
} else {
list = t->m->objectsToFinalize;
t->m->objectsToFinalize = 0;
}
}
for (; list; list = pairSecond(t, list)) {
finalizeObject(t, pairFirst(t, list));
}
}
}
void void
noop() noop()
{ } { }

View File

@ -1173,6 +1173,7 @@ class Machine {
Processor* processor; Processor* processor;
Thread* rootThread; Thread* rootThread;
Thread* exclusive; Thread* exclusive;
Thread* finalizeThread;
Reference* jniReferences; Reference* jniReferences;
const char** properties; const char** properties;
unsigned propertyCount; unsigned propertyCount;
@ -1201,6 +1202,7 @@ class Machine {
object weakReferences; object weakReferences;
object tenuredWeakReferences; object tenuredWeakReferences;
object shutdownHooks; object shutdownHooks;
object objectsToFinalize;
bool unsafe; bool unsafe;
bool triedBuiltinOnLoad; bool triedBuiltinOnLoad;
JavaVMVTable javaVMVTable; JavaVMVTable javaVMVTable;
@ -1231,6 +1233,9 @@ inline void stress(Thread* t);
void void
runJavaThread(Thread* t); runJavaThread(Thread* t);
void
runFinalizeThread(Thread* t);
class Thread { class Thread {
public: public:
enum State { enum State {
@ -1302,11 +1307,15 @@ class Thread {
t->m->localThread->set(t); t->m->localThread->set(t);
if (t == t->m->finalizeThread) {
runFinalizeThread(t);
} else if (t->javaThread) {
runJavaThread(t); runJavaThread(t);
if (t->exception) { if (t->exception) {
printTrace(t, t->exception); printTrace(t, t->exception);
} }
}
t->exit(); t->exit();
} }
@ -2357,6 +2366,25 @@ interrupt(Thread*, Thread* target)
target->systemThread->interrupt(); target->systemThread->interrupt();
} }
inline void
setDaemon(Thread* t, object thread, bool daemon)
{
ACQUIRE_RAW(t, t->m->stateLock);
if (threadDaemon(t, thread) != daemon) {
threadDaemon(t, thread) = daemon;
if (daemon) {
++ t->m->daemonCount;
} else {
expect(t, t->m->daemonCount);
-- t->m->daemonCount;
}
t->m->stateLock->notifyAll(t->systemThread);
}
}
object object
intern(Thread* t, object s); intern(Thread* t, object s);

View File

@ -1,4 +1,5 @@
public class Finalizers { public class Finalizers {
private static final Object lock = new Object();
private static boolean finalized = false; private static boolean finalized = false;
private static void expect(boolean v) { private static void expect(boolean v) {
@ -6,15 +7,21 @@ public class Finalizers {
} }
protected void finalize() { protected void finalize() {
synchronized (lock) {
finalized = true; finalized = true;
lock.notifyAll();
}
} }
public static void main(String[] args) { public static void main(String[] args) throws Exception {
new Finalizers(); new Finalizers();
expect(! finalized); expect(! finalized);
synchronized (lock) {
System.gc(); System.gc();
lock.wait(5000);
}
expect(finalized); expect(finalized);
@ -24,7 +31,10 @@ public class Finalizers {
expect(! finalized); expect(! finalized);
synchronized (lock) {
System.gc(); System.gc();
lock.wait(5000);
}
expect(finalized); expect(finalized);
} }