diff --git a/src/mongo/transport/asio/asio_networking_baton.cpp b/src/mongo/transport/asio/asio_networking_baton.cpp
|
index 4400ac91eae..07afe73ec84 100644
|
--- a/src/mongo/transport/asio/asio_networking_baton.cpp
|
+++ b/src/mongo/transport/asio/asio_networking_baton.cpp
|
@@ -28,6 +28,9 @@
|
*/
|
|
|
+#include "mongo/platform/compiler_gcc.h"
|
+#include "mongo/stdx/condition_variable.h"
|
+#include <atomic>
|
#include <sys/eventfd.h>
|
|
#include "mongo/transport/asio/asio_networking_baton.h"
|
@@ -160,7 +163,10 @@ void AsioNetworkingBaton::schedule(Task func) noexcept {
|
}
|
|
void AsioNetworkingBaton::notify() noexcept {
|
- efd(_opCtx).notify();
|
+ NotificationHandshake old =
|
+ _notificationHandshake.exchange(kNotificationPending, std::memory_order_relaxed);
|
+ if (old == kInPoll)
|
+ efd(_opCtx).notify();
|
}
|
|
Waitable::TimeoutState AsioNetworkingBaton::run_until(ClockSource* clkSource,
|
@@ -373,13 +379,23 @@ std::list<Promise<void>> AsioNetworkingBaton::_poll(stdx::unique_lock<Mutex>& lk
|
_inPoll = true;
|
lk.unlock();
|
|
+ const auto oldState = _notificationHandshake.exchange(kInPoll, std::memory_order_relaxed);
|
+ invariant(oldState != kInPoll);
|
+
|
const ScopeGuard guard([&] {
|
+ // Both consumes a notification (if-any) and mark us as no-longer in poll
|
+ _notificationHandshake.store(kNone, std::memory_order_relaxed);
|
+
|
lk.lock();
|
_inPoll = false;
|
});
|
|
blockAsioNetworkingBatonBeforePoll.pauseWhileSet();
|
- int timeout = deadline ? Milliseconds(*deadline - now).count() : -1;
|
+ int timeout = oldState == kNotificationPending
|
+ ? 0 // Don't wait if there is a notification pending.
|
+ : deadline ? Milliseconds(*deadline - now).count()
|
+ : -1;
|
+
|
int events = ::poll(_pollSet.data(), _pollSet.size(), timeout);
|
if (events < 0) {
|
auto ec = lastSystemError();
|
@@ -429,23 +445,26 @@ Future<void> AsioNetworkingBaton::_addSession(Session& session, short events) tr
|
}
|
|
void AsioNetworkingBaton::detachImpl() noexcept {
|
- decltype(_scheduled) scheduled;
|
- decltype(_sessions) sessions;
|
- decltype(_timers) timers;
|
|
- {
|
- stdx::lock_guard lk(_mutex);
|
+ stdx::unique_lock lk(_mutex);
|
+
|
+ invariant(_opCtx->getBaton().get() == this);
|
+ _opCtx->setBaton(nullptr);
|
|
- invariant(_opCtx->getBaton().get() == this);
|
- _opCtx->setBaton(nullptr);
|
+ _opCtx = nullptr;
|
|
- _opCtx = nullptr;
|
+ if (MONGO_likely(_scheduled.empty() && _sessions.empty() && _timers.empty()))
|
+ return;
|
|
- using std::swap;
|
- swap(_scheduled, scheduled);
|
- swap(_sessions, sessions);
|
- swap(_timers, timers);
|
- }
|
+ using std::swap;
|
+ decltype(_scheduled) scheduled;
|
+ swap(_scheduled, scheduled);
|
+ decltype(_sessions) sessions;
|
+ swap(_sessions, sessions);
|
+ decltype(_timers) timers;
|
+ swap(_timers, timers);
|
+
|
+ lk.unlock();
|
|
for (auto& job : scheduled) {
|
job(stdx::unique_lock(_mutex));
|
diff --git a/src/mongo/transport/asio/asio_networking_baton.h b/src/mongo/transport/asio/asio_networking_baton.h
|
index 3d3086a30b1..92a20506b59 100644
|
--- a/src/mongo/transport/asio/asio_networking_baton.h
|
+++ b/src/mongo/transport/asio/asio_networking_baton.h
|
@@ -146,6 +146,10 @@ private:
|
|
bool _inPoll = false;
|
|
+ enum NotificationHandshake { kNone, kNotificationPending, kInPoll };
|
+ std::atomic<NotificationHandshake> // NOLINT (all operations on this can safely be relaxed)
|
+ _notificationHandshake;
|
+
|
// Stores the sessions we need to poll on.
|
stdx::unordered_map<SessionId, TransportSession> _sessions;
|