diff options
Diffstat (limited to 'src/mongo/db')
-rw-r--r-- | src/mongo/db/client_out_of_line_executor.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/client_out_of_line_executor.h | 11 | ||||
-rw-r--r-- | src/mongo/db/client_out_of_line_executor_test.cpp | 15 |
3 files changed, 29 insertions, 1 deletions
diff --git a/src/mongo/db/client_out_of_line_executor.cpp b/src/mongo/db/client_out_of_line_executor.cpp index e2fe618165f..f82612266ba 100644 --- a/src/mongo/db/client_out_of_line_executor.cpp +++ b/src/mongo/db/client_out_of_line_executor.cpp @@ -55,6 +55,8 @@ ClientOutOfLineExecutor::ClientOutOfLineExecutor() noexcept : _impl{std::make_unique<Impl>()}, _taskQueue{std::make_shared<QueueType>()} {} ClientOutOfLineExecutor::~ClientOutOfLineExecutor() noexcept { + if (!_requireShutdown.load()) + return; invariant(_isShutdown); } @@ -83,7 +85,7 @@ ClientOutOfLineExecutor* ClientOutOfLineExecutor::get(const Client* client) noex } void ClientOutOfLineExecutor::schedule(Task task) { - _taskQueue->push(std::move(task)); + getHandle().schedule(std::move(task)); } void ClientOutOfLineExecutor::consumeAllTasks() noexcept { diff --git a/src/mongo/db/client_out_of_line_executor.h b/src/mongo/db/client_out_of_line_executor.h index 08a9a734d82..b0a9e9874c1 100644 --- a/src/mongo/db/client_out_of_line_executor.h +++ b/src/mongo/db/client_out_of_line_executor.h @@ -33,6 +33,8 @@ #include <memory> #include "mongo/db/client.h" +#include "mongo/platform/atomic_word.h" +#include "mongo/platform/compiler.h" #include "mongo/util/out_of_line_executor.h" #include "mongo/util/producer_consumer_queue.h" @@ -78,10 +80,19 @@ public: }; auto getHandle() noexcept { + // We always acquire a handle before scheduling tasks on the executor. The following ensures + // that acquiring a handle, thus exposing the executor to the outside world, always requires + // shutdown. A combination of load/store is preferred over using CAS due to performance + // considerations, and considering the fact that overwriting `_requireShutdown` is safe. + if (MONGO_unlikely(!_requireShutdown.load())) + _requireShutdown.store(true); return QueueHandle(_taskQueue); } private: + // Shutdown is not required so long as the executor is not exposed to the outside world. + AtomicWord<bool> _requireShutdown{false}; + class Impl; std::unique_ptr<Impl> _impl; diff --git a/src/mongo/db/client_out_of_line_executor_test.cpp b/src/mongo/db/client_out_of_line_executor_test.cpp index cffeb633c87..a72b3450c66 100644 --- a/src/mongo/db/client_out_of_line_executor_test.cpp +++ b/src/mongo/db/client_out_of_line_executor_test.cpp @@ -35,6 +35,7 @@ #include "mongo/platform/atomic_word.h" #include "mongo/stdx/thread.h" #include "mongo/unittest/barrier.h" +#include "mongo/unittest/death_test.h" #include "mongo/unittest/unittest.h" namespace mongo { @@ -167,5 +168,19 @@ TEST_F(ClientOutOfLineExecutorTest, ScheduleAfterClientThreadReturns) { ASSERT(taskCalled); } +TEST_F(ClientOutOfLineExecutorTest, SkipShutdownWhenNoTaskIsScheduled) { + ClientOutOfLineExecutor executor; +} + +DEATH_TEST_F(ClientOutOfLineExecutorTest, RequireShutdownAfterAcquiringHandles, "invariant") { + ClientOutOfLineExecutor executor; + executor.getHandle(); +} + +DEATH_TEST_F(ClientOutOfLineExecutorTest, RequireShutdownAfterSchedulingTasks, "invariant") { + ClientOutOfLineExecutor executor; + executor.schedule([](Status) {}); +} + } // namespace } // namespace mongo |