summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAmirsaman Memaripour <amirsaman.memaripour@mongodb.com>2020-07-15 19:16:26 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2020-07-16 01:31:15 +0000
commitb348b91ffdfab32e5a1ec9e63c9def884adf1acb (patch)
treec0ce0eb76813c622ee92e8d5b89a8772672cc406
parentd520082a3f8568b9303ab7e37c111d436d1dd50b (diff)
downloadmongo-b348b91ffdfab32e5a1ec9e63c9def884adf1acb.tar.gz
SERVER-49432 Avoid read-after-delete in ServiceExecutorSync shutdown
-rw-r--r--src/mongo/transport/service_executor_synchronous.cpp34
-rw-r--r--src/mongo/transport/service_executor_synchronous.h2
2 files changed, 21 insertions, 15 deletions
diff --git a/src/mongo/transport/service_executor_synchronous.cpp b/src/mongo/transport/service_executor_synchronous.cpp
index 1fce3b78cc8..15724d3470c 100644
--- a/src/mongo/transport/service_executor_synchronous.cpp
+++ b/src/mongo/transport/service_executor_synchronous.cpp
@@ -51,7 +51,8 @@ thread_local std::deque<ServiceExecutor::Task> ServiceExecutorSynchronous::_loca
thread_local int ServiceExecutorSynchronous::_localRecursionDepth = 0;
thread_local int64_t ServiceExecutorSynchronous::_localThreadIdleCounter = 0;
-ServiceExecutorSynchronous::ServiceExecutorSynchronous(ServiceContext* ctx) {}
+ServiceExecutorSynchronous::ServiceExecutorSynchronous(ServiceContext* ctx)
+ : _shutdownCondition(std::make_shared<stdx::condition_variable>()) {}
Status ServiceExecutorSynchronous::start() {
_numHardwareCores = static_cast<size_t>(ProcessInfo::getNumAvailableCores());
@@ -67,7 +68,7 @@ Status ServiceExecutorSynchronous::shutdown(Milliseconds timeout) {
_stillRunning.store(false);
stdx::unique_lock<Latch> lock(_shutdownMutex);
- bool result = _shutdownCondition.wait_for(lock, timeout.toSystemDuration(), [this]() {
+ bool result = _shutdownCondition->wait_for(lock, timeout.toSystemDuration(), [this]() {
return _numRunningWorkerThreads.load() == 0;
});
@@ -112,20 +113,25 @@ Status ServiceExecutorSynchronous::schedule(Task task, ScheduleFlags flags) {
// into the thread local job queue.
LOGV2_DEBUG(22983, 3, "Starting new executor thread in passthrough mode");
- Status status = launchServiceWorkerThread([this, task = std::move(task)] {
- _numRunningWorkerThreads.addAndFetch(1);
+ Status status = launchServiceWorkerThread(
+ [this, condVarAnchor = _shutdownCondition, task = std::move(task)] {
+ _numRunningWorkerThreads.addAndFetch(1);
- _localWorkQueue.emplace_back(std::move(task));
- while (!_localWorkQueue.empty() && _stillRunning.loadRelaxed()) {
- _localRecursionDepth = 1;
- _localWorkQueue.front()();
- _localWorkQueue.pop_front();
- }
+ _localWorkQueue.emplace_back(std::move(task));
+ while (!_localWorkQueue.empty() && _stillRunning.loadRelaxed()) {
+ _localRecursionDepth = 1;
+ _localWorkQueue.front()();
+ _localWorkQueue.pop_front();
+ }
- if (_numRunningWorkerThreads.subtractAndFetch(1) == 0) {
- _shutdownCondition.notify_all();
- }
- });
+ // We maintain an anchor to "_shutdownCondition" to ensure it remains alive even if the
+ // service executor is freed. Any access to the service executor (through "this") is
+ // prohibited (and unsafe) after the following line. For more context, see SERVER-49432.
+ auto numWorkerThreadsStillRunning = _numRunningWorkerThreads.subtractAndFetch(1);
+ if (numWorkerThreadsStillRunning == 0) {
+ condVarAnchor->notify_all();
+ }
+ });
return status;
}
diff --git a/src/mongo/transport/service_executor_synchronous.h b/src/mongo/transport/service_executor_synchronous.h
index f305b7a695b..5fee75bbf2d 100644
--- a/src/mongo/transport/service_executor_synchronous.h
+++ b/src/mongo/transport/service_executor_synchronous.h
@@ -68,7 +68,7 @@ private:
mutable Mutex _shutdownMutex = MONGO_MAKE_LATCH(HierarchicalAcquisitionLevel(0),
"ServiceExecutorSynchronous::_shutdownMutex");
- stdx::condition_variable _shutdownCondition;
+ std::shared_ptr<stdx::condition_variable> _shutdownCondition;
AtomicWord<size_t> _numRunningWorkerThreads{0};
size_t _numHardwareCores{0};