summaryrefslogtreecommitdiff
path: root/src/mongo/platform
diff options
context:
space:
mode:
authorBen Caimano <ben.caimano@mongodb.com>2019-10-21 20:04:47 +0000
committerevergreen <evergreen@mongodb.com>2019-10-21 20:04:47 +0000
commitb641599cf48d33bc79a4131ac8a8f5018dea83c4 (patch)
tree50500c6436bdb90ae0893fee20541cffeb4538ce /src/mongo/platform
parenta843d5a714e415e128916e49b76e2b2d333bb5d8 (diff)
downloadmongo-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/SConscript1
-rw-r--r--src/mongo/platform/condition_variable.cpp50
-rw-r--r--src/mongo/platform/condition_variable.h173
-rw-r--r--src/mongo/platform/condition_variable_test.cpp61
-rw-r--r--src/mongo/platform/mutex.cpp55
-rw-r--r--src/mongo/platform/mutex.h67
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