diff options
author | Andy Schwerin <schwerin@mongodb.com> | 2016-10-13 10:18:19 -0400 |
---|---|---|
committer | Andy Schwerin <schwerin@mongodb.com> | 2016-10-13 10:18:19 -0400 |
commit | 9228a2b401b4af0adfa53a61053fba3a7df4f75c (patch) | |
tree | b9a66d8073dfa532c87dd04f2e48d90d75e4097e /src/mongo/db/operation_context.cpp | |
parent | 8794dd4bdcab131a4ecf0963505e7fb2a34bf5e6 (diff) | |
download | mongo-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.cpp | 16 |
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(); |