diff options
author | Ben Caimano <ben.caimano@mongodb.com> | 2019-10-21 20:04:47 +0000 |
---|---|---|
committer | evergreen <evergreen@mongodb.com> | 2019-10-21 20:04:47 +0000 |
commit | b641599cf48d33bc79a4131ac8a8f5018dea83c4 (patch) | |
tree | 50500c6436bdb90ae0893fee20541cffeb4538ce /src/mongo/platform | |
parent | a843d5a714e415e128916e49b76e2b2d333bb5d8 (diff) | |
download | mongo-b641599cf48d33bc79a4131ac8a8f5018dea83c4.tar.gz |
SERVER-42967 SERVER-42895 SERVER-44086 Expand DiagnosticInfo hooks in Interruptible and Mutex
This commit:
- Adds Listener hooks for Interruptible
- Expands Listener hooks for Mutex
- Updates the DiagnosticInfo and its tests to use the new hooks
- Removes stacktracing pieces from DiagnosticInfo and its tests
- Removes mongo::ConditionVariable entirely in favor of Interruptible
Diffstat (limited to 'src/mongo/platform')
-rw-r--r-- | src/mongo/platform/SConscript | 1 | ||||
-rw-r--r-- | src/mongo/platform/condition_variable.cpp | 50 | ||||
-rw-r--r-- | src/mongo/platform/condition_variable.h | 173 | ||||
-rw-r--r-- | src/mongo/platform/condition_variable_test.cpp | 61 | ||||
-rw-r--r-- | src/mongo/platform/mutex.cpp | 55 | ||||
-rw-r--r-- | src/mongo/platform/mutex.h | 67 |
6 files changed, 89 insertions, 318 deletions
diff --git a/src/mongo/platform/SConscript b/src/mongo/platform/SConscript index 910d1388223..648445c0746 100644 --- a/src/mongo/platform/SConscript +++ b/src/mongo/platform/SConscript @@ -8,7 +8,6 @@ env.CppUnitTest( 'atomic_proxy_test.cpp', 'atomic_word_test.cpp', 'bits_test.cpp', - 'condition_variable_test.cpp', 'endian_test.cpp', 'mutex_test.cpp', 'process_id_test.cpp', diff --git a/src/mongo/platform/condition_variable.cpp b/src/mongo/platform/condition_variable.cpp deleted file mode 100644 index ef6e64aaff7..00000000000 --- a/src/mongo/platform/condition_variable.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/** - * Copyright (C) 2018-present MongoDB, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the Server Side Public License, version 1, - * as published by MongoDB, Inc. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * Server Side Public License for more details. - * - * You should have received a copy of the Server Side Public License - * along with this program. If not, see - * <http://www.mongodb.com/licensing/server-side-public-license>. - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the Server Side Public License in all respects for - * all of the code used other than as permitted herein. If you modify file(s) - * with this exception, you may extend this exception to your version of the - * file(s), but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. If you delete this - * exception statement from all source files in the program, then also delete - * it in the license file. - */ - -#include "mongo/platform/basic.h" - -#include "mongo/platform/condition_variable.h" - -namespace mongo { - -std::unique_ptr<ConditionVariableActions> ConditionVariable::_conditionVariableActions; - -void ConditionVariable::notify_one() noexcept { - _condvar.notify_one(); -} - -void ConditionVariable::notify_all() noexcept { - _condvar.notify_all(); -} - -void ConditionVariable::setConditionVariableActions( - std::unique_ptr<ConditionVariableActions> actions) { - _conditionVariableActions = std::move(actions); -} -} // namespace mongo diff --git a/src/mongo/platform/condition_variable.h b/src/mongo/platform/condition_variable.h deleted file mode 100644 index beca4f4dda9..00000000000 --- a/src/mongo/platform/condition_variable.h +++ /dev/null @@ -1,173 +0,0 @@ -/** - * Copyright (C) 2018-present MongoDB, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the Server Side Public License, version 1, - * as published by MongoDB, Inc. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * Server Side Public License for more details. - * - * You should have received a copy of the Server Side Public License - * along with this program. If not, see - * <http://www.mongodb.com/licensing/server-side-public-license>. - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the Server Side Public License in all respects for - * all of the code used other than as permitted herein. If you modify file(s) - * with this exception, you may extend this exception to your version of the - * file(s), but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. If you delete this - * exception statement from all source files in the program, then also delete - * it in the license file. - */ - -#pragma once - -#include <chrono> - -#include "mongo/platform/mutex.h" -#include "mongo/stdx/condition_variable.h" -#include "mongo/util/duration.h" -#include "mongo/util/scopeguard.h" - -namespace mongo { - -class Mutex; - -class ConditionVariableActions { -public: - virtual ~ConditionVariableActions() = default; - virtual void onUnfulfilledConditionVariable(const StringData& name) = 0; - virtual void onFulfilledConditionVariable() = 0; -}; - -class ConditionVariable { -public: - static constexpr Milliseconds kUnfulfilledConditionVariableTimeout = Milliseconds(100); - - template <class Lock> - void wait(Lock& lock); - - template <class Lock, class Predicate> - void wait(Lock& lock, Predicate pred); - - template <class Lock, class Rep, class Period> - stdx::cv_status wait_for(Lock& lock, const stdx::chrono::duration<Rep, Period>& rel_time); - - template <class Lock, class Rep, class Period, class Predicate> - bool wait_for(Lock& lock, const stdx::chrono::duration<Rep, Period>& rel_time, Predicate pred); - - template <class Lock, class Clock, class Duration> - stdx::cv_status wait_until(Lock& lock, - const stdx::chrono::time_point<Clock, Duration>& timeout_time); - - template <class Lock, class Clock, class Duration, class Predicate> - bool wait_until(Lock& lock, - const stdx::chrono::time_point<Clock, Duration>& timeout_time, - Predicate pred); - - void notify_one() noexcept; - void notify_all() noexcept; - - static void setConditionVariableActions(std::unique_ptr<ConditionVariableActions> actions); - -protected: - template <typename Callback> - friend void runWithNotifyable(ConditionVariable& cv, - Notifyable& notifyable, - Callback&& cb) noexcept { - runWithNotifyable(cv._condvar, notifyable, std::forward<Callback>(cb)); - } - -private: - const Seconds _conditionVariableTimeout = Seconds(604800); - stdx::condition_variable_any _condvar; - - static std::unique_ptr<ConditionVariableActions> _conditionVariableActions; - - template <class Lock, class Duration> - auto _wait(Lock& lock, const Duration& rel_time) { - const auto guard = makeGuard([&] { - if (_conditionVariableActions) { - _conditionVariableActions->onFulfilledConditionVariable(); - } - }); - - if (auto cvstatus = _condvar.wait_for( - lock, std::min(rel_time, kUnfulfilledConditionVariableTimeout.toSystemDuration())); - cvstatus == stdx::cv_status::no_timeout || - rel_time <= kUnfulfilledConditionVariableTimeout.toSystemDuration()) { - return cvstatus; - } - - if (_conditionVariableActions) { - if constexpr (std::is_same<decltype(lock), mongo::Mutex>::value) { - _conditionVariableActions->onUnfulfilledConditionVariable(lock.getName()); - } else { - _conditionVariableActions->onUnfulfilledConditionVariable("AnonymousLock"); - } - } - - if (auto cvstatus = _condvar.wait_for( - lock, rel_time - kUnfulfilledConditionVariableTimeout.toSystemDuration()); - cvstatus == stdx::cv_status::no_timeout) { - return cvstatus; - } - - uasserted(ErrorCodes::InternalError, "Unable to take latch, wait time exceeds set timeout"); - } - - template <class Lock, class Duration, class Predicate> - auto _waitWithPredicate(Lock& lock, const Duration& rel_time, Predicate pred) { - while (!pred()) { - if (_wait(lock, rel_time) == stdx::cv_status::timeout) { - return pred(); - } - } - return true; - } -}; - -template <class Lock> -void ConditionVariable::wait(Lock& lock) { - _wait(lock, _conditionVariableTimeout.toSystemDuration()); -} - -template <class Lock, class Predicate> -void ConditionVariable::wait(Lock& lock, Predicate pred) { - _waitWithPredicate(lock, _conditionVariableTimeout.toSystemDuration(), std::move(pred)); -} - -template <class Lock, class Rep, class Period> -stdx::cv_status ConditionVariable::wait_for(Lock& lock, - const stdx::chrono::duration<Rep, Period>& rel_time) { - return _wait(lock, rel_time); -} - -template <class Lock, class Rep, class Period, class Predicate> -bool ConditionVariable::wait_for(Lock& lock, - const stdx::chrono::duration<Rep, Period>& rel_time, - Predicate pred) { - return _waitWithPredicate(lock, rel_time, pred); -} - -template <class Lock, class Clock, class Duration> -stdx::cv_status ConditionVariable::wait_until( - Lock& lock, const stdx::chrono::time_point<Clock, Duration>& timeout_time) { - return _wait(lock, timeout_time - stdx::chrono::steady_clock::now()); -} - -template <class Lock, class Clock, class Duration, class Predicate> -bool ConditionVariable::wait_until(Lock& lock, - const stdx::chrono::time_point<Clock, Duration>& timeout_time, - Predicate pred) { - return _waitWithPredicate(lock, timeout_time - stdx::chrono::steady_clock::now(), pred); -} - -} // namespace mongo diff --git a/src/mongo/platform/condition_variable_test.cpp b/src/mongo/platform/condition_variable_test.cpp deleted file mode 100644 index 69631e233f2..00000000000 --- a/src/mongo/platform/condition_variable_test.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/** - * Copyright (C) 2018-present MongoDB, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the Server Side Public License, version 1, - * as published by MongoDB, Inc. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * Server Side Public License for more details. - * - * You should have received a copy of the Server Side Public License - * along with this program. If not, see - * <http://www.mongodb.com/licensing/server-side-public-license>. - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the Server Side Public License in all respects for - * all of the code used other than as permitted herein. If you modify file(s) - * with this exception, you may extend this exception to your version of the - * file(s), but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. If you delete this - * exception statement from all source files in the program, then also delete - * it in the license file. - */ - -#include "mongo/unittest/unittest.h" - -#include "mongo/platform/condition_variable.h" -#include "mongo/platform/mutex.h" -#include "mongo/stdx/thread.h" -#include "mongo/unittest/barrier.h" - -namespace mongo { - -TEST(ConditionVariable, BasicSingleThread) { - unittest::Barrier barrier(2U); - ConditionVariable cv; - stdx::mutex m; // NOLINT - bool done = false; - - stdx::thread worker([&]() { - stdx::unique_lock<stdx::mutex> lk(m); - barrier.countDownAndWait(); - ASSERT(!done); - cv.wait(lk, [&] { return done; }); - ASSERT(done); - }); - - barrier.countDownAndWait(); - { - stdx::unique_lock<stdx::mutex> lk(m); - done = true; - } - cv.notify_one(); - worker.join(); -} -} // namespace mongo diff --git a/src/mongo/platform/mutex.cpp b/src/mongo/platform/mutex.cpp index ba7230f8e94..3f2a18fe58a 100644 --- a/src/mongo/platform/mutex.cpp +++ b/src/mongo/platform/mutex.cpp @@ -32,27 +32,60 @@ namespace mongo { void Mutex::lock() { - auto hasLock = _mutex.try_lock(); - if (hasLock) { + if (_mutex.try_lock()) { + _onQuickLock(_name); return; } - if (auto actions = LockActions::getState().actions.load()) { - actions->onContendedLock(_name); - } + + _onContendedLock(_name); _mutex.lock(); + _onSlowLock(_name); } void Mutex::unlock() { - if (auto actions = LockActions::getState().actions.load()) { - actions->onUnlock(_name); - } + _onUnlock(_name); _mutex.unlock(); } bool Mutex::try_lock() { - return _mutex.try_lock(); + if (!_mutex.try_lock()) { + return false; + } + + _onQuickLock(_name); + return true; +} + +void Mutex::addLockListener(LockListener* listener) { + auto& state = _getListenerState(); + + state.list.push_back(listener); +} + +void Mutex::_onContendedLock(const StringData& name) noexcept { + auto& state = _getListenerState(); + for (auto listener : state.list) { + listener->onContendedLock(name); + } +} + +void Mutex::_onQuickLock(const StringData& name) noexcept { + auto& state = _getListenerState(); + for (auto listener : state.list) { + listener->onQuickLock(name); + } } -void Mutex::LockActions::add(LockActions* actions) { - getState().actions.store(actions); +void Mutex::_onSlowLock(const StringData& name) noexcept { + auto& state = _getListenerState(); + for (auto listener : state.list) { + listener->onSlowLock(name); + } +} + +void Mutex::_onUnlock(const StringData& name) noexcept { + auto& state = _getListenerState(); + for (auto listener : state.list) { + listener->onUnlock(name); + } } } // namespace mongo diff --git a/src/mongo/platform/mutex.h b/src/mongo/platform/mutex.h index fe72b201d3a..dd6bd4996a0 100644 --- a/src/mongo/platform/mutex.h +++ b/src/mongo/platform/mutex.h @@ -46,11 +46,18 @@ public: virtual void lock() = 0; virtual void unlock() = 0; virtual bool try_lock() = 0; + + virtual StringData getName() const { + return "AnonymousLatch"_sd; + } }; class Mutex : public Latch { + class LockNotifier; + public: - class LockActions; + class LockListener; + static constexpr auto kAnonymousMutexStr = "AnonymousMutex"_sd; Mutex() : Mutex(kAnonymousMutexStr) {} @@ -61,11 +68,36 @@ public: void lock() override; void unlock() override; bool try_lock() override; - const StringData& getName() const { + StringData getName() const override { return _name; } + /** + * This function adds a LockListener subclass to the triggers for certain actions. + * + * LockListeners can only be added and not removed. If you wish to deactivate a LockListeners + * subclass, please provide the switch on that subclass to noop its functions. It is only safe + * to add a LockListener during a MONGO_INITIALIZER. + */ + static void addLockListener(LockListener* listener); + private: + static auto& _getListenerState() noexcept { + struct State { + std::vector<LockListener*> list; + }; + + // Note that state should no longer be mutated after init-time (ala MONGO_INITIALIZERS). If + // this changes, than this state needs to be synchronized. + static State state; + return state; + } + + static void _onContendedLock(const StringData& name) noexcept; + static void _onQuickLock(const StringData& name) noexcept; + static void _onSlowLock(const StringData& name) noexcept; + static void _onUnlock(const StringData& name) noexcept; + const StringData _name; stdx::mutex _mutex; // NOLINT }; @@ -73,40 +105,31 @@ private: /** * A set of actions to happen upon notable events on a Lockable-conceptualized type */ -class Mutex::LockActions { +class Mutex::LockListener { friend class Mutex; public: - virtual ~LockActions() = default; + virtual ~LockListener() = default; + /** * Action to do when a lock cannot be immediately acquired */ virtual void onContendedLock(const StringData& name) = 0; /** - * Action to do when a lock is unlocked + * Action to do when a lock was acquired without blocking */ - virtual void onUnlock(const StringData& name) = 0; + virtual void onQuickLock(const StringData& name) = 0; /** - * This function adds a LockActions subclass to the triggers for certain actions. - * - * Note that currently there is only one LockActions in use at a time. As part of SERVER-42895, - * this will change so that there is a list of LockActions maintained. - * - * LockActions can only be added and not removed. If you wish to deactivate a LockActions - * subclass, please provide the switch on that subclass to noop its functions. + * Action to do when a lock was acquired after blocking */ - static void add(LockActions* actions); + virtual void onSlowLock(const StringData& name) = 0; -private: - static auto& getState() { - struct State { - AtomicWord<LockActions*> actions{nullptr}; - }; - static State state; - return state; - } + /** + * Action to do when a lock is unlocked + */ + virtual void onUnlock(const StringData& name) = 0; }; } // namespace mongo |