summaryrefslogtreecommitdiff
path: root/src/mongo/db/operation_context.cpp
diff options
context:
space:
mode:
authorAndy Schwerin <schwerin@mongodb.com>2016-10-13 10:18:19 -0400
committerAndy Schwerin <schwerin@mongodb.com>2016-10-13 10:18:19 -0400
commit9228a2b401b4af0adfa53a61053fba3a7df4f75c (patch)
treeb9a66d8073dfa532c87dd04f2e48d90d75e4097e /src/mongo/db/operation_context.cpp
parent8794dd4bdcab131a4ecf0963505e7fb2a34bf5e6 (diff)
downloadmongo-9228a2b401b4af0adfa53a61053fba3a7df4f75c.tar.gz
SERVER-26305 Use interruptible condition variables in ReplicationCoordinatorImpl instead of KillOpListener
While this change also improves the readability of _awaitReplication_inlock and stepDown, it resovles SERVER-26305 by breaking a deadlock cycle caused by the fact that KillOpListener methods get run under a mutex in ServiceContext.
Diffstat (limited to 'src/mongo/db/operation_context.cpp')
-rw-r--r--src/mongo/db/operation_context.cpp16
1 files changed, 14 insertions, 2 deletions
diff --git a/src/mongo/db/operation_context.cpp b/src/mongo/db/operation_context.cpp
index 2a5c8814bf3..8151fe97dfa 100644
--- a/src/mongo/db/operation_context.cpp
+++ b/src/mongo/db/operation_context.cpp
@@ -248,16 +248,28 @@ static NOINLINE_DECL stdx::cv_status cvWaitUntilWithClockSource(ClockSource* clo
auto alarmInfo = std::make_shared<AlarmInfo>();
alarmInfo->waitCV = &cv;
alarmInfo->waitMutex = m.mutex();
- invariantOK(clockSource->setAlarm(deadline, [alarmInfo] {
+ const auto waiterThreadId = stdx::this_thread::get_id();
+ bool invokedAlarmInline = false;
+ invariantOK(clockSource->setAlarm(deadline, [alarmInfo, waiterThreadId, &invokedAlarmInline] {
stdx::lock_guard<stdx::mutex> controlLk(alarmInfo->controlMutex);
alarmInfo->cvWaitResult = stdx::cv_status::timeout;
if (!alarmInfo->waitMutex) {
return;
}
+ if (stdx::this_thread::get_id() == waiterThreadId) {
+ // In NetworkInterfaceMock, setAlarm may invoke its callback immediately if the deadline
+ // has expired, so we detect that case and avoid self-deadlock by returning early, here.
+ // It is safe to set invokedAlarmInline without synchronization in this case, because it
+ // is exactly the case where the same thread is writing and consulting the value.
+ invokedAlarmInline = true;
+ return;
+ }
stdx::lock_guard<stdx::mutex> waitLk(*alarmInfo->waitMutex);
alarmInfo->waitCV->notify_all();
}));
- cv.wait(m);
+ if (!invokedAlarmInline) {
+ cv.wait(m);
+ }
m.unlock();
stdx::lock_guard<stdx::mutex> controlLk(alarmInfo->controlMutex);
m.lock();