fix race condition in interrupting/joining threads as they are exiting

My recent commit to ensure that OS resources are released immediately
upon thread exit introduced a race condition where interrupting or
joining a thread as it exited could lead to attempts to use
already-released resources.  This commit adds locking to avoid the
race.
This commit is contained in:
Joel Dice 2010-11-16 10:50:19 -07:00
parent 3ff1f9c59f
commit aea02e545f
2 changed files with 46 additions and 9 deletions

View File

@ -45,10 +45,9 @@ void
join(Thread* t, Thread* o)
{
if (t != o) {
if (o->state != Thread::ZombieState
and o->state != Thread::JoinedState)
{
if (acquireSystem(t, o)) {
o->systemThread->join();
releaseSystem(t, o);
}
o->state = Thread::JoinedState;
}
@ -2407,7 +2406,15 @@ Thread::exit()
turnOffTheLights(this);
} else {
threadPeer(this, javaThread) = 0;
{ ACQUIRE_RAW(this, m->stateLock);
while (flags & SystemFlag) {
m->stateLock->wait(systemThread, 0);
}
enter(this, Thread::ZombieState);
}
lock->dispose();
lock = 0;

View File

@ -1298,6 +1298,7 @@ class Thread {
static const unsigned DaemonFlag = 1 << 3;
static const unsigned StressFlag = 1 << 4;
static const unsigned ActiveFlag = 1 << 5;
static const unsigned SystemFlag = 1 << 6;
class Protector {
public:
@ -2758,13 +2759,42 @@ notifyAll(Thread* t, object o)
}
}
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)) {
atomicOr(&(target->flags), Thread::SystemFlag);
return true;
} else {
return false;
}
}
inline void
interrupt(Thread*, Thread* target)
releaseSystem(Thread* t, Thread* target)
{
if (target->state != Thread::ZombieState
and target->state != Thread::JoinedState)
ACQUIRE_RAW(t, t->m->stateLock);
assert(t, not zombified(target));
atomicAnd(&(target->flags), ~Thread::SystemFlag);
}
inline void
interrupt(Thread* t, Thread* target)
{
if (acquireSystem(t, target)) {
target->systemThread->interrupt();
releaseSystem(t, target);
}
}