summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBilly Donahue <billy.donahue@mongodb.com>2022-05-13 04:01:14 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2022-05-13 04:58:26 +0000
commit95edbf51b92e6944043590fe781c901d2a815f9f (patch)
treef0c7e827152480a01f1485c11b4bbbb6f6ef078a /src
parent33ced84ad3537acb5a70907b6febb34adbcfbbcc (diff)
downloadmongo-95edbf51b92e6944043590fe781c901d2a815f9f.tar.gz
SERVER-63852 ThreadName rewrite
Diffstat (limited to 'src')
-rw-r--r--src/mongo/db/client.cpp4
-rw-r--r--src/mongo/db/client.h2
-rw-r--r--src/mongo/db/client_strand.cpp6
-rw-r--r--src/mongo/db/client_strand.h6
-rw-r--r--src/mongo/db/client_strand_test.cpp12
-rw-r--r--src/mongo/logv2/log_source.h8
-rw-r--r--src/mongo/util/concurrency/thread_name.cpp244
-rw-r--r--src/mongo/util/concurrency/thread_name.h162
-rw-r--r--src/mongo/util/errno_util.cpp18
-rw-r--r--src/mongo/util/errno_util.h12
10 files changed, 272 insertions, 202 deletions
diff --git a/src/mongo/db/client.cpp b/src/mongo/db/client.cpp
index 7da46be32df..acf26319b39 100644
--- a/src/mongo/db/client.cpp
+++ b/src/mongo/db/client.cpp
@@ -188,14 +188,14 @@ ThreadClient::ThreadClient(StringData desc,
ServiceContext* serviceContext,
transport::SessionHandle session) {
invariantNoCurrentClient();
- _originalThreadName = ThreadName::get(ThreadContext::get());
+ _originalThreadName = getThreadNameRef();
Client::initThread(desc, serviceContext, std::move(session));
}
ThreadClient::~ThreadClient() {
invariant(currentClient);
currentClient.reset(nullptr);
- ThreadName::set(ThreadContext::get(), _originalThreadName);
+ setThreadNameRef(std::move(_originalThreadName));
}
Client* ThreadClient::get() const {
diff --git a/src/mongo/db/client.h b/src/mongo/db/client.h
index af203a5255e..9f566763a93 100644
--- a/src/mongo/db/client.h
+++ b/src/mongo/db/client.h
@@ -337,7 +337,7 @@ public:
}
private:
- boost::intrusive_ptr<ThreadName> _originalThreadName;
+ ThreadNameRef _originalThreadName;
};
/**
diff --git a/src/mongo/db/client_strand.cpp b/src/mongo/db/client_strand.cpp
index 41aa4af3d9e..f4bd5665540 100644
--- a/src/mongo/db/client_strand.cpp
+++ b/src/mongo/db/client_strand.cpp
@@ -69,7 +69,7 @@ void ClientStrand::_setCurrent() noexcept {
Client::setCurrent(std::move(_client));
// Set up the thread name.
- _oldThreadName = ThreadName::set(ThreadContext::get(), _threadName);
+ _oldThreadName = setThreadNameRef(_threadName);
if (_oldThreadName) {
LOGV2_DEBUG(5127802, kDiagnosticLogLevel, "Set thread name", "name"_attr = *_threadName);
}
@@ -85,10 +85,10 @@ void ClientStrand::_releaseCurrent() noexcept {
if (_oldThreadName) {
// Reset the last thread name because it was previously set in the OS.
- ThreadName::set(ThreadContext::get(), std::move(_oldThreadName));
+ setThreadNameRef(std::move(_oldThreadName));
} else {
// Release the thread name for reuse.
- ThreadName::release(ThreadContext::get());
+ releaseThreadNameRef();
}
LOGV2_DEBUG(
diff --git a/src/mongo/db/client_strand.h b/src/mongo/db/client_strand.h
index cab3140671d..334e29a7c15 100644
--- a/src/mongo/db/client_strand.h
+++ b/src/mongo/db/client_strand.h
@@ -133,7 +133,7 @@ public:
ClientStrand(ServiceContext::UniqueClient client)
: _clientPtr(client.get()),
_client(std::move(client)),
- _threadName(make_intrusive<ThreadName>(_client->desc())) {}
+ _threadName(ThreadNameRef{_client->desc()}) {}
/**
* Get a pointer to the underlying Client.
@@ -204,8 +204,8 @@ private:
ServiceContext::UniqueClient _client;
- boost::intrusive_ptr<ThreadName> _threadName;
- boost::intrusive_ptr<ThreadName> _oldThreadName;
+ ThreadNameRef _threadName;
+ ThreadNameRef _oldThreadName;
};
inline void ClientStrand::Executor::schedule(Task task) {
diff --git a/src/mongo/db/client_strand_test.cpp b/src/mongo/db/client_strand_test.cpp
index cce87321862..661b03ea8cd 100644
--- a/src/mongo/db/client_strand_test.cpp
+++ b/src/mongo/db/client_strand_test.cpp
@@ -54,7 +54,7 @@ public:
* Clean up any leftover thread_local pieces.
*/
void releaseClient() {
- ThreadName::release(ThreadContext::get());
+ releaseThreadNameRef();
if (haveClient()) {
Client::releaseCurrent();
}
@@ -123,7 +123,7 @@ TEST_F(ClientStrandTest, BindMultipleTimes) {
// We have no bound Client.
assertStrandNotBound(strand);
- for (auto i = 0; i < 100; ++i) {
+ for (auto i = 0; i < 10; ++i) {
// Bind a bunch of times.
{
@@ -145,7 +145,7 @@ TEST_F(ClientStrandTest, BindMultipleTimesAndDismiss) {
assertStrandNotBound(strand);
auto guard = strand->bind();
- for (auto i = 0; i < 100; ++i) {
+ for (auto i = 0; i < 10; ++i) {
assertStrandBound(strand);
// Dismiss the current guard.
@@ -266,7 +266,7 @@ TEST_F(ClientStrandTest, BindLocalAfterWorkerThread) {
TEST_F(ClientStrandTest, BindManyWorkerThreads) {
auto strand = ClientStrand::make(getServiceContext()->makeClient(kClientName1));
- constexpr size_t kCount = 100;
+ constexpr size_t kCount = 10;
auto barrier = std::make_shared<unittest::Barrier>(kCount);
size_t threadsBound = 0;
@@ -308,7 +308,7 @@ TEST_F(ClientStrandTest, SwapStrands) {
assertStrandNotBound(strand1);
assertStrandNotBound(strand2);
- for (size_t i = 0; i < 100; ++i) {
+ for (size_t i = 0; i < 10; ++i) {
// Alternate between binding strand1 and strand2. Start on strand2 so it has a different
// thread name than the previous test.
auto& strand = (i % 2 == 0) ? strand2 : strand1;
@@ -325,7 +325,7 @@ TEST_F(ClientStrandTest, SwapStrands) {
}
TEST_F(ClientStrandTest, Executor) {
- constexpr size_t kCount = 100;
+ constexpr size_t kCount = 10;
auto strand = ClientStrand::make(getServiceContext()->makeClient(kClientName1));
diff --git a/src/mongo/logv2/log_source.h b/src/mongo/logv2/log_source.h
index 4051bcfb55a..8e83cb6ad54 100644
--- a/src/mongo/logv2/log_source.h
+++ b/src/mongo/logv2/log_source.h
@@ -74,10 +74,10 @@ public:
add_attribute_unlocked(attributes::timeStamp(), boost::log::attributes::make_function([]() {
return Date_t::now();
}));
- add_attribute_unlocked(
- attributes::threadName(), boost::log::attributes::make_function([isShutdown]() {
- return isShutdown ? "shutdown"_sd : ThreadName::getStaticString();
- }));
+ add_attribute_unlocked(attributes::threadName(),
+ boost::log::attributes::make_function([isShutdown]() {
+ return isShutdown ? "shutdown"_sd : getThreadName();
+ }));
}
explicit LogSource(const LogDomain::Internal* domain) : LogSource(domain, false) {}
diff --git a/src/mongo/util/concurrency/thread_name.cpp b/src/mongo/util/concurrency/thread_name.cpp
index 7f21b5bcc56..36f8e24f577 100644
--- a/src/mongo/util/concurrency/thread_name.cpp
+++ b/src/mongo/util/concurrency/thread_name.cpp
@@ -27,9 +27,6 @@
* it in the license file.
*/
-
-#include "mongo/platform/basic.h"
-
#include "mongo/util/concurrency/thread_name.h"
#if defined(__APPLE__) || defined(__linux__)
@@ -43,10 +40,6 @@
#include <mach/thread_info.h>
#endif
#endif
-#if defined(__linux__)
-#include <sys/syscall.h>
-#include <sys/types.h>
-#endif
#include <fmt/format.h>
@@ -54,7 +47,8 @@
#include "mongo/config.h"
#include "mongo/logv2/log.h"
#include "mongo/platform/atomic_word.h"
-#include "mongo/util/str.h"
+#include "mongo/platform/process_id.h"
+#include "mongo/util/thread_context.h"
#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kControl
@@ -64,6 +58,10 @@ using namespace fmt::literals;
namespace {
+bool isMainThread() {
+ return ProcessId::getCurrent() == ProcessId::getCurrentThreadId();
+}
+
#ifdef _WIN32
// From https://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
// Note: The thread name is only set for the thread if the debugger is attached.
@@ -94,49 +92,15 @@ void setWindowsThreadName(DWORD dwThreadID, const char* threadName) {
}
#endif
-constexpr auto kMainId = size_t{0};
-
-auto makeAnonymousThreadName() {
- static auto gNextAnonymousId = AtomicWord<size_t>{kMainId};
- auto id = gNextAnonymousId.fetchAndAdd(1);
- if (id == kMainId) {
- // The first thread name should always be "main".
- return make_intrusive<ThreadName>("main");
- } else {
- return make_intrusive<ThreadName>("thread{}"_format(id));
- }
-}
-
-struct ThreadNameSconce {
- ThreadNameSconce() : cachedPtr(makeAnonymousThreadName()) {
- // Note that we're not setting the thread name here. It will log differently, but appear the
- // same in top and like.
- }
-
- // At any given time, either cachedPtr or activePtr can be valid, but not both.
- boost::intrusive_ptr<ThreadName> activePtr;
- boost::intrusive_ptr<ThreadName> cachedPtr;
-};
-
-auto getSconce = ThreadContext::declareDecoration<ThreadNameSconce>();
-auto& getThreadName(const boost::intrusive_ptr<ThreadContext>& context) {
- auto& sconce = getSconce(context.get());
- if (sconce.activePtr) {
- return sconce.activePtr;
- }
-
- return sconce.cachedPtr;
-}
-
-void setOSThreadName(StringData threadName) {
+void setOSThreadName(const std::string& threadName) {
#if defined(_WIN32)
// Naming should not be expensive compared to thread creation and connection set up, but if
// testing shows otherwise we should make this depend on DEBUG again.
- setWindowsThreadName(GetCurrentThreadId(), threadName.rawData());
+ setWindowsThreadName(GetCurrentThreadId(), threadName.c_str());
#elif defined(__APPLE__)
// Maximum thread name length on OS X is MAXTHREADNAMESIZE (64 characters). This assumes
// OS X 10.6 or later.
- std::string threadNameCopy = threadName.toString();
+ std::string threadNameCopy = threadName;
if (threadNameCopy.size() > MAXTHREADNAMESIZE) {
threadNameCopy.resize(MAXTHREADNAMESIZE - 4);
threadNameCopy += "...";
@@ -152,95 +116,137 @@ void setOSThreadName(StringData threadName) {
// Do not set thread name on the main() thread. Setting the name on main thread breaks
// pgrep/pkill since these programs base this name on /proc/*/status which displays the thread
// name, not the executable name.
- if (getpid() != syscall(SYS_gettid)) {
- // Maximum thread name length supported on Linux is 16 including the null terminator.
- // Ideally we use short and descriptive thread names that fit: this helps for log
- // readability as well. Still, as the limit is so low and a few current names exceed the
- // limit, it's best to shorten long names.
- int error = 0;
- if (threadName.size() > 15) {
- std::string shortName = str::stream()
- << threadName.substr(0, 7) << '.' << threadName.substr(threadName.size() - 7);
- error = pthread_setname_np(pthread_self(), shortName.c_str());
- } else {
- error = pthread_setname_np(pthread_self(), threadName.rawData());
- }
-
- if (error) {
- LOGV2(23103,
- "Ignoring error from setting thread name: {error}",
- "Ignoring error from setting thread name",
- "error"_attr = errorMessage(posixError(error)));
- }
+ if (isMainThread())
+ return;
+ // Maximum thread name length supported on Linux is 16 including the null terminator.
+ // Ideally we use short and descriptive thread names that fit: this helps for log
+ // readability as well. Still, as the limit is so low and a few current names exceed the
+ // limit, it's best to shorten long names.
+ static constexpr size_t kMaxThreadNameLength = 16 - 1;
+ boost::optional<std::string> shortNameBuf;
+ const char* truncName = threadName.c_str();
+ if (threadName.size() > kMaxThreadNameLength) {
+ StringData sd = threadName;
+ shortNameBuf = "{}.{}"_format(sd.substr(0, 7), sd.substr(sd.size() - 7));
+ truncName = shortNameBuf->c_str();
}
-#endif
-}
-
-} // namespace
-ThreadName::Id ThreadName::_nextId() {
- static auto gNextId = AtomicWord<Id>{0};
- return gNextId.fetchAndAdd(1);
+ int error = pthread_setname_np(pthread_self(), truncName);
+ if (auto ec = posixError(error)) {
+ LOGV2(23103,
+ "Ignoring error from setting thread name: {error}",
+ "Ignoring error from setting thread name",
+ "error"_attr = errorMessage(ec));
+ }
+#endif
}
-StringData ThreadName::getStaticString() {
- auto& context = ThreadContext::get();
- if (!context) {
- // Use a static fallback to avoid allocations. This is the string that will be used before
- // initializers run in main a.k.a. pre-init.
- static constexpr auto kFallback = "-"_sd;
- return kFallback;
+/**
+ * Manages the relationship of our high-level ThreadNameRef strings to
+ * the thread local context, and efficiently notifying the OS of name
+ * changes. We try to apply temporary names to threads to make them
+ * meaningful representations of the kind of work the thread is doing.
+ * But sharing these names with the OS is slow and name length is limited. So
+ * ThreadNameInfo is an auxiliary resource to the OS thread name, available to
+ * the LOGV2 system and to GDB.
+ *
+ * ThreadNameInfo is a decoration of ThreadContext.
+ * ThreadContext are held by thread_local storage and so threads started
+ * after server initialization will have an associated ThreadNameInfo.
+ *
+ * A name is "active" when it has been pushed to the OS by `setHandle`. The
+ * association can be abandoned by calling `release`. This doesn't affect the
+ * OS, but indicates that the name binding is abandoned and shouldn't be
+ * preserved by returning it from subsequent `setHandle` calls. We do however
+ * retain the inactive reference in hopes of perhaps identifying redundant
+ * `setHandle` calls that would set the OS thread name to the same value it
+ * already has.
+ *
+ * Upon construction, a ThreadNameInfo has an inactive unique name that
+ * the OS doesn't know about yet. A push/pop style call sequence of
+ * `h=getHandle()` then (eventually) `setHandle(h)` can make this name
+ * the active (known to the OS) thread name.
+ */
+class ThreadNameInfo {
+public:
+ /** Returns the thread name ref, whether it's active or not. */
+ const ThreadNameRef& getHandle() const {
+ return _h;
}
- return getThreadName(context)->toString();
-}
+ /**
+ * Changes the thread name ref to `name`, marking it active,
+ * and updating the OS thread name if necessary.
+ *
+ * If there was a previous active thread name, it is returned so that
+ * callers can perhaps restore it and implement a temporary rename.
+ * Inactive thread names are considered abandoned and are not returned.
+ */
+ ThreadNameRef setHandle(ThreadNameRef name) {
+ bool alreadyActive = std::exchange(_active, true);
+ if (name == _h)
+ return {};
+ auto old = std::exchange(_h, std::move(name));
+ setOSThreadName(*_h);
+ if (alreadyActive)
+ return old;
+ return {};
+ }
-boost::intrusive_ptr<ThreadName> ThreadName::get(boost::intrusive_ptr<ThreadContext> context) {
- return getThreadName(context);
-}
+ /**
+ * Mark the current ThreadNameRef as inactive. This is only a marking and
+ * does not affect the OS thread name. The ThreadNameRef is retained
+ * so that redundant setHandle calls can be recognized and elided.
+ */
+ void release() {
+ _active = false;
+ }
-boost::intrusive_ptr<ThreadName> ThreadName::set(boost::intrusive_ptr<ThreadContext> context,
- boost::intrusive_ptr<ThreadName> name) {
- invariant(name);
+ /**
+ * Get a pointer to this thread's ThreadNameInfo.
+ * Returns null if there's no ThreadContext to get it from.
+ */
+ static ThreadNameInfo* forThisThread() {
+ auto& context = ThreadContext::get();
+ return context ? &_decoration(*context) : nullptr;
+ }
- auto& sconce = getSconce(context.get());
+private:
+ inline static auto _decoration = ThreadContext::declareDecoration<ThreadNameInfo>();
+
+ /**
+ * Main thread always gets "main". Other threads are sequentially
+ * named as "thread1", "thread2", etc.
+ */
+ static std::string _makeAnonymousThreadName() {
+ if (isMainThread())
+ return "main";
+ static AtomicWord<uint64_t> next{1};
+ return "thread{}"_format(next.fetchAndAdd(1));
+ }
- if (sconce.activePtr) {
- invariant(!sconce.cachedPtr);
- if (*sconce.activePtr == *name) {
- // The name was already set, skip setting it to the OS thread name.
- return {};
- } else {
- // Replace the current active name with the new one, and set the OS thread name.
- setOSThreadName(name->toString());
- return std::exchange(sconce.activePtr, name);
- }
- } else if (sconce.cachedPtr) {
- if (*sconce.cachedPtr == *name) {
- // The name was cached, set it as active and skip setting it to the OS thread name.
- sconce.activePtr = std::exchange(sconce.cachedPtr, {});
- return {};
- } else {
- // The new name is different than the cached name, set the active, reset the cached, and
- // set the OS thread name.
- setOSThreadName(name->toString());
+ ThreadNameRef _h{_makeAnonymousThreadName()};
+ bool _active = false;
+};
- sconce.activePtr = name;
- sconce.cachedPtr.reset();
- return {};
- }
- }
+} // namespace
- MONGO_UNREACHABLE;
+ThreadNameRef getThreadNameRef() {
+ if (auto info = ThreadNameInfo::forThisThread())
+ return info->getHandle();
+ return {};
}
-void ThreadName::release(boost::intrusive_ptr<ThreadContext> context) {
- auto& sconce = getSconce(context.get());
- if (sconce.activePtr) {
- sconce.cachedPtr = std::exchange(sconce.activePtr, {});
- }
+ThreadNameRef setThreadNameRef(ThreadNameRef name) {
+ invariant(name);
+ if (auto info = ThreadNameInfo::forThisThread())
+ return info->setHandle(std::move(name));
+ return {};
}
-ThreadName::ThreadName(StringData name) : _id(_nextId()), _storage(name.toString()){};
+void releaseThreadNameRef() {
+ if (auto info = ThreadNameInfo::forThisThread())
+ info->release();
+}
} // namespace mongo
diff --git a/src/mongo/util/concurrency/thread_name.h b/src/mongo/util/concurrency/thread_name.h
index 2efd004263a..f4bc4582a3c 100644
--- a/src/mongo/util/concurrency/thread_name.h
+++ b/src/mongo/util/concurrency/thread_name.h
@@ -29,103 +29,141 @@
#pragma once
+#include <memory>
#include <string>
#include "mongo/base/string_data.h"
-#include "mongo/util/intrusive_counter.h"
-#include "mongo/util/thread_context.h"
+#include "mongo/util/static_immortal.h"
namespace mongo {
/**
- * ThreadName is a uniquely identifyable, immutable, ref-counted string.
+ * A nullable handle pinning a ref-counted immutable string.
+ * Copies of a ThreadNameString refer to the same string object.
+ * Equality comparisons consider only that string's identity, not its value.
+ *
+ * This class is just a kind of refcounted string handle and does not itself
+ * interact with the OS or with thread storage.
+ *
+ * Presents a pointer-like API with `get()`, and dereference operators, and
+ * explicit bool conversion. Dereferencing yields a reference to a
+ * string value if nonempty. Dereferencing an empty reference is allowed and
+ * yields the singleton string value "-".
+ *
+ * Copyable and movable, with the usual refcounting semantics. Copies refer
+ * to the same string and will compare equal to each other.
*
- * This class is used for three purposes:
- * - Setting the official thread name with the OS.
- * - Populating the "ctx" field for log lines.
- * - Providing a thread name to gdb.
*/
-class ThreadName : public RefCountable {
+class ThreadNameRef {
public:
- using Id = size_t;
+ /** An empty ref (empty refs still stringify as "-"). */
+ ThreadNameRef() = default;
- /**
- * Create a new instance.
- *
- * Note that this does not set it to be the official one for the thread.
- */
- explicit ThreadName(StringData name);
- ThreadName(const ThreadName&) = delete;
- ThreadName(ThreadName&&) = delete;
+ /** A ref to the string value `name`. */
+ explicit ThreadNameRef(std::string name)
+ : _ptr{std::make_shared<std::string>(std::move(name))} {}
/**
- * Get the official ThreadName for the current thread via the ThreadContext.
+ * Dereferences this. If nonempty, returns its string value.
+ * Otherwise, returns a singleton "-" string.
*/
- static boost::intrusive_ptr<ThreadName> get(boost::intrusive_ptr<ThreadContext> context);
+ const std::string* get() const {
+ if (_ptr)
+ return &*_ptr;
+ static const StaticImmortal whenEmpty = std::string("-");
+ return &*whenEmpty;
+ }
- /**
- * Set the official ThreadName for the current thread via the ThreadContext.
- *
- * Note that this also will set the OS thread name if the name is different from the current
- * one.
- *
- * If a different non-anonymous thread name was previously set, this returns that name. If the
- * given name was already set, a previous name was released, or the initial name was set, this
- * returns an empty pointer.
- */
- static boost::intrusive_ptr<ThreadName> set(boost::intrusive_ptr<ThreadContext> context,
- boost::intrusive_ptr<ThreadName> name);
+ const std::string* operator->() const {
+ return get();
+ }
- /**
- * Release the current thread name.
- *
- * This does not unset the OS thread name or change the current storage. Instead, this marks the
- * current name as available for reuse or replacement.
- */
- static void release(boost::intrusive_ptr<ThreadContext> context);
+ const std::string& operator*() const {
+ return *get();
+ }
- /**
- * Get a string for the current thread without new allocations.
- *
- * In pre-init, this returns "-". That value will mostly be associated with the main thread.
- * If a thread is somehow started in pre-init and dodges our ThreadSafetyContext checks, it will
- * also return "-" for this function.
- */
- static StringData getStaticString();
+ /** Returns true if nonempty. */
+ explicit operator bool() const {
+ return !!_ptr;
+ }
- StringData toString() const {
- return _storage;
+ operator StringData() const {
+ return **this;
}
- friend bool operator==(const ThreadName& lhs, const ThreadName& rhs) noexcept {
- return lhs._id == rhs._id;
+ /**
+ * Two ThreadNameRef are equal if and only if they are copies of the same
+ * original ThreadNameRef object. Equality of string value is insufficient.
+ */
+ friend bool operator==(const ThreadNameRef& a, const ThreadNameRef& b) noexcept {
+ return a._ptr == b._ptr;
}
- friend bool operator!=(const ThreadName& lhs, const ThreadName& rhs) noexcept {
- return lhs._id != rhs._id;
+ friend bool operator!=(const ThreadNameRef& a, const ThreadNameRef& b) noexcept {
+ return !(a == b);
}
private:
- static Id _nextId();
-
- const Id _id;
- const std::string _storage;
+ std::shared_ptr<const std::string> _ptr;
};
/**
+ * Returns the name reference attached to current thread. Returns an empty
+ * ThreadNameRef if current thread has no ThreadContext. The empty ThreadNameRef
+ * still has a valid string value of "-".
+ *
+ * This string is not limited in length, so it will be a better name
+ * than the name the OS uses to refer to the same thread.
+ */
+ThreadNameRef getThreadNameRef();
+
+/**
+ * Swaps in a new active name, returns the old one if it was active.
+ *
+ * The active thread name is used for:
+ * - Setting the thread name in the OS. As an optimization, clearing
+ * the thread name in the OS is performed lazily.
+ * - Populating the "ctx" field for log lines.
+ * - Providing a thread name to GDB.
+ *
+ * Has no effect if there is no `ThreadContext` for this thread.
+ */
+ThreadNameRef setThreadNameRef(ThreadNameRef name);
+
+/**
+ * Marks the ThreadNameRef attached to the current thread as inactive.
+ * - The inactive thread name remains attached to the thread.
+ * - The thread name according to the OS is not changed.
+ * - A subsequent `setThreadNameRef` call will not return it.
+ * - An immediately subsequent `setThreadNameRef` call with the same name will
+ * cheaply reactivate it, saving two OS thread rename operations.
+ * This is an optimization on the assumption that a thread name will be
+ * temporarily set to the same `ThreadNameRef` repeatedly, so setting it and
+ * resetting it with the OS on each change would be wasteful.
+ *
+ * Has no effect if there is no `ThreadContext` for this thread.
+ */
+void releaseThreadNameRef();
+
+/**
* Sets the name of the current thread.
*/
-inline void setThreadName(StringData name) {
- ThreadName::set(ThreadContext::get(), make_intrusive<ThreadName>(name));
+inline void setThreadName(std::string name) {
+ setThreadNameRef(ThreadNameRef{std::move(name)});
}
/**
- * Retrieves the name of the current thread, as previously set, or "thread#" if no name was
- * previously set. The returned StringData is always null terminated so it is safe to pass to APIs
- * that expect c-strings.
+ * Returns current thread's name, as previously set, or "main", or
+ * "thread#" if no name was previously set.
+ *
+ * Before the ThreadContext API is initialized, this returns "-". That value
+ * will mostly be associated with the main thread, or threads that were started
+ * before ThreadContext API initialization.
+ *
+ * Used by the MongoDB GDB pretty printer extentions in `gdb/mongo.py`.
*/
inline StringData getThreadName() {
- return ThreadName::get(ThreadContext::get())->toString();
+ return *getThreadNameRef();
}
} // namespace mongo
diff --git a/src/mongo/util/errno_util.cpp b/src/mongo/util/errno_util.cpp
index a9c326f3ae8..9f4ad2611dd 100644
--- a/src/mongo/util/errno_util.cpp
+++ b/src/mongo/util/errno_util.cpp
@@ -27,12 +27,19 @@
* it in the license file.
*/
+#include "mongo/platform/basic.h"
+
#include "mongo/util/errno_util.h"
#include <cerrno>
#include <fmt/format.h>
#include <system_error>
+#ifdef _WIN32
+#include <errhandlingapi.h>
+#include <winsock2.h>
+#endif
+
#ifndef _WIN32
#include <netdb.h>
#endif
@@ -41,6 +48,17 @@ namespace mongo {
using namespace fmt::literals;
+#ifdef _WIN32
+namespace errno_util_win32_detail {
+int gle() {
+ return GetLastError();
+}
+int wsaGle() {
+ return WSAGetLastError();
+}
+} // namespace errno_util_win32_detail
+#endif
+
class AddrInfoErrorCategory : public std::error_category {
public:
const char* name() const noexcept override {
diff --git a/src/mongo/util/errno_util.h b/src/mongo/util/errno_util.h
index 408cebf528c..18b879e704a 100644
--- a/src/mongo/util/errno_util.h
+++ b/src/mongo/util/errno_util.h
@@ -29,6 +29,7 @@
#pragma once
+#include <cstdlib>
#include <system_error>
#include <utility>
@@ -36,6 +37,13 @@
namespace mongo {
+#ifdef _WIN32
+namespace errno_util_win32_detail {
+int gle();
+int wsaGle();
+} // namespace errno_util_win32_detail
+#endif
+
/**
* Returns category to use for POSIX errno error codes.
* On POSIX, `errno` codes are the `std::system_category`.
@@ -86,7 +94,7 @@ inline std::error_code lastPosixError() {
*/
inline std::error_code lastSystemError() {
#ifdef _WIN32
- return systemError(GetLastError());
+ return systemError(errno_util_win32_detail::gle());
#else
return systemError(errno);
#endif
@@ -123,7 +131,7 @@ inline std::error_code addrInfoError(int e) {
*/
inline std::error_code lastSocketError() {
#ifdef _WIN32
- return systemError(WSAGetLastError());
+ return systemError(errno_util_win32_detail::wsaGle());
#else
return lastSystemError();
#endif