mirror of
https://github.com/corda/corda.git
synced 2025-05-31 06:31:08 +00:00
run java finalizers in a separate thread to guarantee no application locks are held when doing so
This commit is contained in:
parent
d4e2e05b31
commit
4297fa04b3
@ -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
|
||||||
|
111
src/machine.cpp
111
src/machine.cpp
@ -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()
|
||||||
{ }
|
{ }
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user