summaryrefslogtreecommitdiff
path: root/src/mongo/util/diagnostic_info.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/util/diagnostic_info.cpp')
-rw-r--r--src/mongo/util/diagnostic_info.cpp118
1 files changed, 61 insertions, 57 deletions
diff --git a/src/mongo/util/diagnostic_info.cpp b/src/mongo/util/diagnostic_info.cpp
index 9681414e797..ea6cbe376df 100644
--- a/src/mongo/util/diagnostic_info.cpp
+++ b/src/mongo/util/diagnostic_info.cpp
@@ -33,12 +33,17 @@
#include "mongo/util/diagnostic_info.h"
+#include "mongo/config.h"
+
#if defined(__linux__)
#include <elf.h>
-#include <execinfo.h>
#include <link.h>
#endif
+#if defined(MONGO_CONFIG_HAVE_EXECINFO_BACKTRACE)
+#include <execinfo.h>
+#endif
+
#include <fmt/format.h>
#include <fmt/ostream.h>
@@ -52,8 +57,6 @@
using namespace fmt::literals;
namespace mongo {
-// Maximum number of stack frames to appear in a backtrace.
-const unsigned int kMaxBackTraceFrames = 100;
namespace {
MONGO_FAIL_POINT_DEFINE(currentOpSpawnsThreadWaitingForLatch);
@@ -67,10 +70,10 @@ public:
void setIsContended(bool value);
private:
- Mutex _testMutex{kBlockedOpMutexName};
+ Mutex _testMutex = MONGO_MAKE_LATCH(kBlockedOpMutexName);
stdx::condition_variable _cv;
- stdx::mutex _m;
+ stdx::mutex _m; // NOLINT
struct State {
bool isContended = false;
@@ -127,34 +130,45 @@ void BlockedOp::setIsContended(bool value) {
_cv.notify_one();
}
-const auto gDiagnosticHandle = Client::declareDecoration<DiagnosticInfo::Diagnostic>();
+struct DiagnosticInfoHandle {
+ stdx::mutex mutex; // NOLINT
+ boost::optional<DiagnosticInfo> maybeInfo = boost::none;
+};
+const auto getDiagnosticInfoHandle = Client::declareDecoration<DiagnosticInfoHandle>();
MONGO_INITIALIZER(LockActions)(InitializerContext* context) {
-
- class LockActionsSubclass : public LockActions {
+ class LockActionsSubclass : public Mutex::LockActions {
void onContendedLock(const StringData& name) override {
- if (haveClient()) {
- DiagnosticInfo::Diagnostic::set(
- Client::getCurrent(),
- std::make_shared<DiagnosticInfo>(takeDiagnosticInfo(name)));
- }
-
- if (currentOpSpawnsThreadWaitingForLatch.shouldFail() &&
- (name == kBlockedOpMutexName)) {
- gBlockedOp.setIsContended(true);
+ auto client = Client::getCurrent();
+ if (client) {
+ auto& handle = getDiagnosticInfoHandle(client);
+ stdx::lock_guard<stdx::mutex> lk(handle.mutex);
+ handle.maybeInfo.emplace(DiagnosticInfo::capture(name));
+
+ if (currentOpSpawnsThreadWaitingForLatch.shouldFail() &&
+ (name == kBlockedOpMutexName)) {
+ gBlockedOp.setIsContended(true);
+ }
}
}
- void onUnlock(const StringData&) override {
- DiagnosticInfo::Diagnostic::clearDiagnostic();
+ void onUnlock(const StringData& name) override {
+ auto client = Client::getCurrent();
+ if (client) {
+ auto& handle = getDiagnosticInfoHandle(client);
+ stdx::lock_guard<stdx::mutex> lk(handle.mutex);
+ handle.maybeInfo.reset();
+ }
}
};
- std::unique_ptr<LockActions> mutexPointer = std::make_unique<LockActionsSubclass>();
- Mutex::setLockActions(std::move(mutexPointer));
+ // Intentionally leaked, people use Latches in detached threads
+ static auto& actions = *new LockActionsSubclass;
+ Mutex::LockActions::add(&actions);
return Status::OK();
}
+/*
MONGO_INITIALIZER(ConditionVariableActions)(InitializerContext* context) {
class ConditionVariableActionsSubclass : public ConditionVariableActions {
@@ -162,7 +176,7 @@ MONGO_INITIALIZER(ConditionVariableActions)(InitializerContext* context) {
if (haveClient()) {
DiagnosticInfo::Diagnostic::set(
Client::getCurrent(),
- std::make_shared<DiagnosticInfo>(takeDiagnosticInfo(name)));
+ std::make_shared<DiagnosticInfo>(capture(name)));
}
}
void onFulfilledConditionVariable() override {
@@ -176,28 +190,10 @@ MONGO_INITIALIZER(ConditionVariableActions)(InitializerContext* context) {
return Status::OK();
}
+*/
} // namespace
-auto DiagnosticInfo::Diagnostic::get(Client* const client) -> std::shared_ptr<DiagnosticInfo> {
- auto& handle = gDiagnosticHandle(client);
- stdx::lock_guard lk(handle.m);
- return handle.diagnostic;
-}
-
-void DiagnosticInfo::Diagnostic::set(Client* const client,
- std::shared_ptr<DiagnosticInfo> newDiagnostic) {
- auto& handle = gDiagnosticHandle(client);
- stdx::lock_guard lk(handle.m);
- handle.diagnostic = newDiagnostic;
-}
-
-void DiagnosticInfo::Diagnostic::clearDiagnostic() {
- if (haveClient()) {
- DiagnosticInfo::Diagnostic::set(Client::getCurrent(), nullptr);
- }
-}
-
#if defined(__linux__)
namespace {
@@ -232,8 +228,6 @@ MONGO_INITIALIZER(InitializeDynamicObjectMap)(InitializerContext* context) {
return Status::OK();
};
-} // anonymous namespace
-
int DynamicObjectMap::addToMap(dl_phdr_info* info, size_t size, void* data) {
auto& addr_map = *reinterpret_cast<decltype(DynamicObjectMap::_map)*>(data);
for (int j = 0; j < info->dlpi_phnum; j++) {
@@ -271,30 +265,33 @@ DiagnosticInfo::StackFrame DynamicObjectMap::getFrame(void* instructionPtr) cons
return DiagnosticInfo::StackFrame{frame.objectPath, fileOffset};
}
+} // namespace
+#endif // linux
+
+#if defined(MONGO_CONFIG_HAVE_EXECINFO_BACKTRACE) && defined(__linux__)
// iterates through the backtrace instruction pointers to
// find the instruction pointer that refers to a segment in the addr_map
DiagnosticInfo::StackTrace DiagnosticInfo::makeStackTrace() const {
DiagnosticInfo::StackTrace trace;
- for (auto addr : _backtraceAddresses) {
- trace.frames.emplace_back(gDynamicObjectMap.getFrame(addr));
+ for (auto address : _backtrace.data) {
+ trace.frames.emplace_back(gDynamicObjectMap.getFrame(address));
}
return trace;
}
-static std::vector<void*> getBacktraceAddresses() {
- std::vector<void*> backtraceAddresses(kMaxBackTraceFrames, 0);
- int addressCount = backtrace(backtraceAddresses.data(), kMaxBackTraceFrames);
- // backtrace will modify the vector's underlying array without updating its size
- backtraceAddresses.resize(static_cast<unsigned int>(addressCount));
- return backtraceAddresses;
+auto DiagnosticInfo::getBacktrace() -> Backtrace {
+ Backtrace list;
+ auto len = ::backtrace(list.data.data(), list.data.size());
+ list.data.resize(len);
+ return list;
}
#else
DiagnosticInfo::StackTrace DiagnosticInfo::makeStackTrace() const {
return DiagnosticInfo::StackTrace();
}
-static std::vector<void*> getBacktraceAddresses() {
- return std::vector<void*>();
+auto DiagnosticInfo::getBacktrace() -> Backtrace {
+ return {};
}
#endif
@@ -311,7 +308,7 @@ bool operator==(const DiagnosticInfo::StackTrace& trace1,
bool operator==(const DiagnosticInfo& info1, const DiagnosticInfo& info2) {
return info1._captureName == info2._captureName && info1._timestamp == info2._timestamp &&
- info1._backtraceAddresses == info2._backtraceAddresses;
+ info1._backtrace.data == info2._backtrace.data;
}
std::string DiagnosticInfo::StackFrame::toString() const {
@@ -335,15 +332,16 @@ std::string DiagnosticInfo::StackTrace::toString() const {
std::string DiagnosticInfo::toString() const {
return "{{ \"name\": \"{}\", \"time\": \"{}\", \"backtraceSize\": {} }}"_format(
- _captureName.toString(), _timestamp.toString(), _backtraceAddresses.size());
+ _captureName.toString(), _timestamp.toString(), _backtrace.data.size());
}
-DiagnosticInfo takeDiagnosticInfo(const StringData& captureName) {
+DiagnosticInfo DiagnosticInfo::capture(const StringData& captureName, Options options) {
// uses backtrace to retrieve an array of instruction pointers for currently active
// function calls of the program
return DiagnosticInfo(getGlobalServiceContext()->getFastClockSource()->now(),
captureName,
- getBacktraceAddresses());
+ options.shouldTakeBacktrace ? DiagnosticInfo::getBacktrace()
+ : Backtrace{{}});
}
DiagnosticInfo::BlockedOpGuard::~BlockedOpGuard() {
@@ -365,4 +363,10 @@ auto DiagnosticInfo::maybeMakeBlockedOpForTest(Client* client) -> std::unique_pt
return guard;
}
+boost::optional<DiagnosticInfo> DiagnosticInfo::get(Client& client) {
+ auto& handle = getDiagnosticInfoHandle(client);
+ stdx::lock_guard<stdx::mutex> lk(handle.mutex);
+ return handle.maybeInfo;
+}
+
} // namespace mongo