fix Thread.interrupt deadlock

Previously, we returned immediately from Monitor.wait if we found we
had been interrupted, but this caused deadlock when waiting to enter
the exclusive state, since we never released Machine::stateLock to
allow active threads to transition into the idle state.  This commit
ensures that we at least briefly release the lock without actually
waiting in that case.
This commit is contained in:
Joel Dice 2011-08-11 07:35:03 -06:00
parent 44f7bd9fe0
commit 8d2ca7aaf5
2 changed files with 40 additions and 40 deletions

View File

@ -306,11 +306,9 @@ class MySystem: public System {
{ ACQUIRE(t->mutex);
if (t->r->interrupted()) {
if (clearInterrupted) {
t->r->setInterrupted(false);
}
return true;
interrupted = t->r->interrupted();
if (interrupted and clearInterrupted) {
t->r->setInterrupted(false);
}
t->flags |= Waiting;
@ -322,27 +320,29 @@ class MySystem: public System {
owner_ = 0;
pthread_mutex_unlock(&mutex);
// pretend anything greater than one million years (in
// milliseconds) is infinity so as to avoid overflow:
if (time and time < INT64_C(31536000000000000)) {
int64_t then = s->now() + time;
timespec ts = { then / 1000, (then % 1000) * 1000 * 1000 };
int rv UNUSED = pthread_cond_timedwait
(&(t->condition), &(t->mutex), &ts);
expect(s, rv == 0 or rv == ETIMEDOUT or rv == EINTR);
} else {
int rv UNUSED = pthread_cond_wait(&(t->condition), &(t->mutex));
expect(s, rv == 0 or rv == EINTR);
if (not interrupted) {
// pretend anything greater than one million years (in
// milliseconds) is infinity so as to avoid overflow:
if (time and time < INT64_C(31536000000000000)) {
int64_t then = s->now() + time;
timespec ts = { then / 1000, (then % 1000) * 1000 * 1000 };
int rv UNUSED = pthread_cond_timedwait
(&(t->condition), &(t->mutex), &ts);
expect(s, rv == 0 or rv == ETIMEDOUT or rv == EINTR);
} else {
int rv UNUSED = pthread_cond_wait(&(t->condition), &(t->mutex));
expect(s, rv == 0 or rv == EINTR);
}
interrupted = t->r->interrupted();
if (interrupted and clearInterrupted) {
t->r->setInterrupted(false);
}
}
notified = ((t->flags & Notified) != 0);
t->flags = 0;
interrupted = t->r->interrupted();
if (interrupted and clearInterrupted) {
t->r->setInterrupted(false);
}
}
pthread_mutex_lock(&mutex);

View File

@ -269,12 +269,10 @@ class MySystem: public System {
int r UNUSED;
{ ACQUIRE(s, t->mutex);
if (t->r->interrupted()) {
if (clearInterrupted) {
t->r->setInterrupted(false);
}
return true;
interrupted = t->r->interrupted();
if (interrupted and clearInterrupted) {
t->r->setInterrupted(false);
}
t->flags |= Waiting;
@ -288,26 +286,28 @@ class MySystem: public System {
bool success UNUSED = ReleaseMutex(mutex);
assert(s, success);
success = ResetEvent(t->event);
assert(s, success);
if (not interrupted) {
success = ResetEvent(t->event);
assert(s, success);
success = ReleaseMutex(t->mutex);
assert(s, success);
success = ReleaseMutex(t->mutex);
assert(s, success);
r = WaitForSingleObject(t->event, (time ? time : INFINITE));
assert(s, r == WAIT_OBJECT_0 or r == WAIT_TIMEOUT);
r = WaitForSingleObject(t->event, (time ? time : INFINITE));
assert(s, r == WAIT_OBJECT_0 or r == WAIT_TIMEOUT);
r = WaitForSingleObject(t->mutex, INFINITE);
assert(s, r == WAIT_OBJECT_0);
r = WaitForSingleObject(t->mutex, INFINITE);
assert(s, r == WAIT_OBJECT_0);
interrupted = t->r->interrupted();
if (interrupted and clearInterrupted) {
t->r->setInterrupted(false);
}
}
notified = ((t->flags & Notified) != 0);
t->flags = 0;
interrupted = t->r->interrupted();
if (interrupted and clearInterrupted) {
t->r->setInterrupted(false);
}
}
r = WaitForSingleObject(mutex, INFINITE);