mirror of
https://github.com/corda/corda.git
synced 2025-06-22 17:09:00 +00:00
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:
@ -45,10 +45,9 @@ void
|
|||||||
join(Thread* t, Thread* o)
|
join(Thread* t, Thread* o)
|
||||||
{
|
{
|
||||||
if (t != o) {
|
if (t != o) {
|
||||||
if (o->state != Thread::ZombieState
|
if (acquireSystem(t, o)) {
|
||||||
and o->state != Thread::JoinedState)
|
|
||||||
{
|
|
||||||
o->systemThread->join();
|
o->systemThread->join();
|
||||||
|
releaseSystem(t, o);
|
||||||
}
|
}
|
||||||
o->state = Thread::JoinedState;
|
o->state = Thread::JoinedState;
|
||||||
}
|
}
|
||||||
@ -2407,7 +2406,15 @@ Thread::exit()
|
|||||||
turnOffTheLights(this);
|
turnOffTheLights(this);
|
||||||
} else {
|
} else {
|
||||||
threadPeer(this, javaThread) = 0;
|
threadPeer(this, javaThread) = 0;
|
||||||
|
|
||||||
|
{ ACQUIRE_RAW(this, m->stateLock);
|
||||||
|
|
||||||
|
while (flags & SystemFlag) {
|
||||||
|
m->stateLock->wait(systemThread, 0);
|
||||||
|
}
|
||||||
|
|
||||||
enter(this, Thread::ZombieState);
|
enter(this, Thread::ZombieState);
|
||||||
|
}
|
||||||
|
|
||||||
lock->dispose();
|
lock->dispose();
|
||||||
lock = 0;
|
lock = 0;
|
||||||
|
@ -1298,6 +1298,7 @@ class Thread {
|
|||||||
static const unsigned DaemonFlag = 1 << 3;
|
static const unsigned DaemonFlag = 1 << 3;
|
||||||
static const unsigned StressFlag = 1 << 4;
|
static const unsigned StressFlag = 1 << 4;
|
||||||
static const unsigned ActiveFlag = 1 << 5;
|
static const unsigned ActiveFlag = 1 << 5;
|
||||||
|
static const unsigned SystemFlag = 1 << 6;
|
||||||
|
|
||||||
class Protector {
|
class Protector {
|
||||||
public:
|
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
|
inline void
|
||||||
interrupt(Thread*, Thread* target)
|
releaseSystem(Thread* t, Thread* target)
|
||||||
{
|
{
|
||||||
if (target->state != Thread::ZombieState
|
ACQUIRE_RAW(t, t->m->stateLock);
|
||||||
and target->state != Thread::JoinedState)
|
|
||||||
|
assert(t, not zombified(target));
|
||||||
|
|
||||||
|
atomicAnd(&(target->flags), ~Thread::SystemFlag);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void
|
||||||
|
interrupt(Thread* t, Thread* target)
|
||||||
{
|
{
|
||||||
|
if (acquireSystem(t, target)) {
|
||||||
target->systemThread->interrupt();
|
target->systemThread->interrupt();
|
||||||
|
releaseSystem(t, target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user