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:
Joel Dice 2012-02-03 17:20:20 -07:00
parent 67a3ca881b
commit be6896b8a0
2 changed files with 25 additions and 55 deletions

View File

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

View File

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