mirror of
https://github.com/corda/corda.git
synced 2025-01-03 19:54:13 +00:00
avoid running out of OS resources due to zombie thread accumulation (part 2)
My previous attempt wasn't quite sufficient, since it was too late to call join on a thread which had already exited given the code was written to aggressively dispose of system handles as soon as the thread exited. The solution is to delay disposing these handles until after we're able to join the thread.
This commit is contained in:
parent
67a3ca881b
commit
be6896b8a0
@ -45,18 +45,10 @@ void
|
||||
join(Thread* t, Thread* o)
|
||||
{
|
||||
if (t != o) {
|
||||
// todo: There's potentially a leak here on systems where we must
|
||||
// call join on a thread in order to clean up all resources
|
||||
// associated with it. If a thread has already been zombified by
|
||||
// the time we get here, acquireSystem will return false, which
|
||||
// means we can't safely join it because the System::Thread may
|
||||
// already have been disposed. In that case, the thread has
|
||||
// already exited (or will soon), but the OS will never free all
|
||||
// its resources because it doesn't know we're completely done
|
||||
// with it.
|
||||
if (acquireSystem(t, o)) {
|
||||
assert(t, o->state != Thread::JoinedState);
|
||||
assert(t, (o->flags & Thread::SystemFlag) == 0);
|
||||
if (o->flags & Thread::JoinFlag) {
|
||||
o->systemThread->join();
|
||||
releaseSystem(t, o);
|
||||
}
|
||||
o->state = Thread::JoinedState;
|
||||
}
|
||||
@ -257,15 +249,17 @@ killZombies(Thread* t, Thread* o)
|
||||
killZombies(t, child);
|
||||
}
|
||||
|
||||
switch (o->state) {
|
||||
case Thread::ZombieState:
|
||||
join(t, o);
|
||||
// fall through
|
||||
|
||||
case Thread::JoinedState:
|
||||
dispose(t, o, true);
|
||||
|
||||
default: break;
|
||||
if ((o->flags & Thread::SystemFlag) == 0) {
|
||||
switch (o->state) {
|
||||
case Thread::ZombieState:
|
||||
join(t, o);
|
||||
// fall through
|
||||
|
||||
case Thread::JoinedState:
|
||||
dispose(t, o, true);
|
||||
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2623,23 +2617,7 @@ Thread::exit()
|
||||
} else {
|
||||
threadPeer(this, javaThread) = 0;
|
||||
|
||||
System::Monitor* myLock = lock;
|
||||
System::Thread* mySystemThread = systemThread;
|
||||
|
||||
{ ACQUIRE_RAW(this, m->stateLock);
|
||||
|
||||
while (flags & SystemFlag) {
|
||||
m->stateLock->wait(systemThread, 0);
|
||||
}
|
||||
|
||||
atomicOr(&flags, Thread::DisposeFlag);
|
||||
|
||||
enter(this, Thread::ZombieState);
|
||||
}
|
||||
|
||||
myLock->dispose();
|
||||
|
||||
mySystemThread->dispose();
|
||||
enter(this, Thread::ZombieState);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2647,14 +2625,12 @@ Thread::exit()
|
||||
void
|
||||
Thread::dispose()
|
||||
{
|
||||
if ((flags & Thread::DisposeFlag) == 0) {
|
||||
if (lock) {
|
||||
lock->dispose();
|
||||
}
|
||||
|
||||
if (systemThread) {
|
||||
systemThread->dispose();
|
||||
}
|
||||
if (lock) {
|
||||
lock->dispose();
|
||||
}
|
||||
|
||||
if (systemThread) {
|
||||
systemThread->dispose();
|
||||
}
|
||||
|
||||
-- m->threadCount;
|
||||
|
@ -1392,7 +1392,7 @@ class Thread {
|
||||
static const unsigned StressFlag = 1 << 4;
|
||||
static const unsigned ActiveFlag = 1 << 5;
|
||||
static const unsigned SystemFlag = 1 << 6;
|
||||
static const unsigned DisposeFlag = 1 << 7;
|
||||
static const unsigned JoinFlag = 1 << 7;
|
||||
|
||||
class Protector {
|
||||
public:
|
||||
@ -1988,6 +1988,7 @@ runThread(Thread* t, uintptr_t*)
|
||||
inline bool
|
||||
startThread(Thread* t, Thread* p)
|
||||
{
|
||||
p->flags |= Thread::JoinFlag;
|
||||
return t->m->system->success(t->m->system->start(&(p->runnable)));
|
||||
}
|
||||
|
||||
@ -2784,19 +2785,12 @@ parameterFootprint(Thread* t, const char* s, bool static_);
|
||||
void
|
||||
addFinalizer(Thread* t, object target, void (*finalize)(Thread*, object));
|
||||
|
||||
inline bool
|
||||
zombified(Thread* t)
|
||||
{
|
||||
return t->state == Thread::ZombieState
|
||||
or t->state == Thread::JoinedState;
|
||||
}
|
||||
|
||||
inline bool
|
||||
acquireSystem(Thread* t, Thread* target)
|
||||
{
|
||||
ACQUIRE_RAW(t, t->m->stateLock);
|
||||
|
||||
if (not zombified(target)) {
|
||||
if (t->state != Thread::JoinedState) {
|
||||
atomicOr(&(target->flags), Thread::SystemFlag);
|
||||
return true;
|
||||
} else {
|
||||
@ -2809,7 +2803,7 @@ releaseSystem(Thread* t, Thread* target)
|
||||
{
|
||||
ACQUIRE_RAW(t, t->m->stateLock);
|
||||
|
||||
assert(t, not zombified(target));
|
||||
assert(t, t->state != Thread::JoinedState);
|
||||
|
||||
atomicAnd(&(target->flags), ~Thread::SystemFlag);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user