summaryrefslogtreecommitdiff
path: root/src/mongo/util/clock_source.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/util/clock_source.cpp')
-rw-r--r--src/mongo/util/clock_source.cpp66
1 files changed, 32 insertions, 34 deletions
diff --git a/src/mongo/util/clock_source.cpp b/src/mongo/util/clock_source.cpp
index ebae9737e73..cd3da75e9c9 100644
--- a/src/mongo/util/clock_source.cpp
+++ b/src/mongo/util/clock_source.cpp
@@ -35,61 +35,59 @@
namespace mongo {
stdx::cv_status ClockSource::waitForConditionUntil(stdx::condition_variable& cv,
- BasicLockableAdapter m,
+ BasicLockableAdapter bla,
Date_t deadline,
Waitable* waitable) {
if (_tracksSystemClock) {
if (deadline == Date_t::max()) {
- Waitable::wait(waitable, this, cv, m);
+ Waitable::wait(waitable, this, cv, bla);
return stdx::cv_status::no_timeout;
}
- return Waitable::wait_until(waitable, this, cv, m, deadline.toSystemTimePoint());
+ return Waitable::wait_until(waitable, this, cv, bla, deadline.toSystemTimePoint());
}
// The rest of this function only runs during testing, when the clock source is virtualized and
// does not track the system clock.
- if (deadline <= now()) {
+ auto currentTime = now();
+ if (deadline <= currentTime) {
return stdx::cv_status::timeout;
}
struct AlarmInfo {
- Mutex controlMutex = MONGO_MAKE_LATCH("AlarmInfo::controlMutex");
- boost::optional<BasicLockableAdapter> waitLock;
- stdx::condition_variable* waitCV;
- stdx::cv_status cvWaitResult = stdx::cv_status::no_timeout;
+ stdx::mutex mutex; // NOLINT
+
+ stdx::condition_variable* cv;
+ stdx::cv_status result = stdx::cv_status::no_timeout;
};
auto alarmInfo = std::make_shared<AlarmInfo>();
- alarmInfo->waitCV = &cv;
- alarmInfo->waitLock = m;
- const auto waiterThreadId = stdx::this_thread::get_id();
- bool invokedAlarmInline = false;
- invariant(setAlarm(deadline, [alarmInfo, waiterThreadId, &invokedAlarmInline] {
- stdx::lock_guard<Latch> controlLk(alarmInfo->controlMutex);
- alarmInfo->cvWaitResult = stdx::cv_status::timeout;
- if (!alarmInfo->waitLock) {
- 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;
+ alarmInfo->cv = &cv;
+
+ invariant(setAlarm(deadline, [alarmInfo] {
+ // Set an alarm to hit our virtualized deadline
+ stdx::lock_guard infoLk(alarmInfo->mutex);
+ auto cv = std::exchange(alarmInfo->cv, nullptr);
+ if (!cv) {
return;
}
- stdx::lock_guard<BasicLockableAdapter> waitLk(*alarmInfo->waitLock);
- alarmInfo->waitCV->notify_all();
+
+ alarmInfo->result = stdx::cv_status::timeout;
+ cv->notify_all();
}));
- if (!invokedAlarmInline) {
- Waitable::wait(waitable, this, cv, m);
+
+ if (stdx::lock_guard infoLk(alarmInfo->mutex); !alarmInfo->cv) {
+ // If setAlarm() ran inline, then we've timed out
+ return alarmInfo->result;
}
- m.unlock();
- stdx::lock_guard<Latch> controlLk(alarmInfo->controlMutex);
- m.lock();
- alarmInfo->waitLock = boost::none;
- alarmInfo->waitCV = nullptr;
- return alarmInfo->cvWaitResult;
+
+ // This is a wait_until because theoretically setAlarm could run out of line before this cv
+ // joins the wait list. Then it could completely miss the notification and block until a lucky
+ // renotify or spurious wakeup.
+ Waitable::wait_until(waitable, this, cv, bla, currentTime + kMaxTimeoutForArtificialClocks);
+
+ stdx::lock_guard infoLk(alarmInfo->mutex);
+ alarmInfo->cv = nullptr;
+ return alarmInfo->result;
}
} // namespace mongo