diff options
author | Amirsaman Memaripour <amirsaman.memaripour@mongodb.com> | 2020-07-15 19:16:26 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2020-07-16 01:31:15 +0000 |
commit | b348b91ffdfab32e5a1ec9e63c9def884adf1acb (patch) | |
tree | c0ce0eb76813c622ee92e8d5b89a8772672cc406 | |
parent | d520082a3f8568b9303ab7e37c111d436d1dd50b (diff) | |
download | mongo-b348b91ffdfab32e5a1ec9e63c9def884adf1acb.tar.gz |
SERVER-49432 Avoid read-after-delete in ServiceExecutorSync shutdown
-rw-r--r-- | src/mongo/transport/service_executor_synchronous.cpp | 34 | ||||
-rw-r--r-- | src/mongo/transport/service_executor_synchronous.h | 2 |
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}; |