diff options
Diffstat (limited to 'src/mongo/util/concurrency/thread_name.h')
| -rw-r--r-- | src/mongo/util/concurrency/thread_name.h | 162 |
1 files changed, 62 insertions, 100 deletions
diff --git a/src/mongo/util/concurrency/thread_name.h b/src/mongo/util/concurrency/thread_name.h index f4bc4582a3c..2efd004263a 100644 --- a/src/mongo/util/concurrency/thread_name.h +++ b/src/mongo/util/concurrency/thread_name.h @@ -29,141 +29,103 @@ #pragma once -#include <memory> #include <string> #include "mongo/base/string_data.h" -#include "mongo/util/static_immortal.h" +#include "mongo/util/intrusive_counter.h" +#include "mongo/util/thread_context.h" namespace mongo { /** - * 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. + * ThreadName is a uniquely identifyable, immutable, ref-counted string. * + * 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 ThreadNameRef { +class ThreadName : public RefCountable { public: - /** An empty ref (empty refs still stringify as "-"). */ - ThreadNameRef() = default; + using Id = size_t; - /** A ref to the string value `name`. */ - explicit ThreadNameRef(std::string name) - : _ptr{std::make_shared<std::string>(std::move(name))} {} + /** + * 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; /** - * Dereferences this. If nonempty, returns its string value. - * Otherwise, returns a singleton "-" string. + * Get the official ThreadName for the current thread via the ThreadContext. */ - const std::string* get() const { - if (_ptr) - return &*_ptr; - static const StaticImmortal whenEmpty = std::string("-"); - return &*whenEmpty; - } + static boost::intrusive_ptr<ThreadName> get(boost::intrusive_ptr<ThreadContext> context); - const std::string* operator->() const { - return get(); - } + /** + * 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); - /** Returns true if nonempty. */ - explicit operator bool() const { - return !!_ptr; - } + /** + * 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(); - operator StringData() const { - return **this; + StringData toString() const { + return _storage; } - /** - * 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); + friend bool operator!=(const ThreadName& lhs, const ThreadName& rhs) noexcept { + return lhs._id != rhs._id; } private: - 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(); + static Id _nextId(); -/** - * 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(); + const Id _id; + const std::string _storage; +}; /** * Sets the name of the current thread. */ -inline void setThreadName(std::string name) { - setThreadNameRef(ThreadNameRef{std::move(name)}); +inline void setThreadName(StringData name) { + ThreadName::set(ThreadContext::get(), make_intrusive<ThreadName>(name)); } /** - * 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`. + * 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. */ inline StringData getThreadName() { - return *getThreadNameRef(); + return ThreadName::get(ThreadContext::get())->toString(); } } // namespace mongo |
