Skip to content

Commit 8cbe913

Browse files
daverigbychiyoung
authored andcommitted
MB-19222: Fix race condition in TaskQueue shutdown
There is a bug in the use of ExecutorThread.state when sleeping a TaskQueue - TaskQueue::_doSleep() doesn't atomically transition the state from RUNNING -> SLEEPING. This can cause a deadlock when shutting down a ExecutorThread: Thread A: Thread B: -------------------------------- ------------------------------ if (t.state == RUNNING) { // true t.state = SHUTDOWN t.state = SLEEPING cb_join_thread(Thread A) // wait forever ... if (t.state == SHUTDOWN) { // FALSE exit(0) // NEVER REACHED } Fix by changing ExecutorThread.state to be an AtomicValue, and use compare-and-exchange to move from RUNNING -> SLEEPING (and SLEEPING -> RUNNING). Change-Id: I9fab90a83978ae2aa6a0dcdd3b079a1c2f369402 Reviewed-on: http://review.couchbase.org/62911 Well-Formed: buildbot <[email protected]> Tested-by: buildbot <[email protected]> Reviewed-by: Will Gardner <[email protected]>
1 parent bd34bbc commit 8cbe913

File tree

3 files changed

+12
-8
lines changed

3 files changed

+12
-8
lines changed

src/executorthread.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ void ExecutorThread::addLogEntry(const std::string &desc,
174174
}
175175

176176
const std::string ExecutorThread::getStateName() {
177-
switch (state) {
177+
switch (state.load()) {
178178
case EXECUTOR_CREATING:
179179
return std::string("creating");
180180
case EXECUTOR_RUNNING:

src/executorthread.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ class ExecutorThread {
123123
ExecutorPool *manager;
124124
int startIndex;
125125
const std::string name;
126-
volatile executor_state_t state;
126+
AtomicValue<executor_state_t> state;
127127

128128
struct timeval now; // record of current time
129129
struct timeval waketime; // set to the earliest

src/taskqueue.cc

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,11 @@ void TaskQueue::_doWake_UNLOCKED(size_t &numToWake) {
6262
bool TaskQueue::_doSleep(ExecutorThread &t) {
6363
gettimeofday(&t.now, NULL);
6464
if (less_tv(t.now, t.waketime) && manager->trySleep(queueType)) {
65-
if (t.state == EXECUTOR_RUNNING) {
66-
t.state = EXECUTOR_SLEEPING;
67-
} else {
65+
// Atomically switch from running to sleeping; iff we were previously
66+
// running.
67+
executor_state_t expected_state = EXECUTOR_RUNNING;
68+
if (!t.state.compare_exchange_strong(expected_state,
69+
EXECUTOR_SLEEPING)) {
6870
return false;
6971
}
7072
sleepers++;
@@ -80,9 +82,11 @@ bool TaskQueue::_doSleep(ExecutorThread &t) {
8082
sleepers--;
8183
manager->woke();
8284

83-
if (t.state == EXECUTOR_SLEEPING) {
84-
t.state = EXECUTOR_RUNNING;
85-
} else {
85+
// Finished our sleep, atomically switch back to running iff we were
86+
// previously sleeping.
87+
expected_state = EXECUTOR_SLEEPING;
88+
if (!t.state.compare_exchange_strong(expected_state,
89+
EXECUTOR_RUNNING)) {
8690
return false;
8791
}
8892
gettimeofday(&t.now, NULL);

0 commit comments

Comments
 (0)