/* Copyright 2009 10gen Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* 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
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*
* 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 GNU Affero General 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.
*/
#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kControl
#include "mongo/platform/basic.h"
#include "mongo/util/concurrency/thread_name.h"
#if defined(__APPLE__) || defined(__linux__)
#include
#endif
#if defined(__APPLE__)
#include
#if !TARGET_OS_TV && !TARGET_OS_IOS && !TARGET_OS_WATCH
#include
#else
#include
#endif
#endif
#if defined(__linux__)
#include
#include
#endif
#include "mongo/base/init.h"
#include "mongo/config.h"
#include "mongo/platform/atomic_word.h"
#include "mongo/util/log.h"
#include "mongo/util/mongoutils/str.h"
namespace mongo {
namespace {
#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.
const DWORD MS_VC_EXCEPTION = 0x406D1388;
#pragma pack(push, 8)
typedef struct tagTHREADNAME_INFO {
DWORD dwType; // Must be 0x1000.
LPCSTR szName; // Pointer to name (in user addr space).
DWORD dwThreadID; // Thread ID (-1=caller thread).
DWORD dwFlags; // Reserved for future use, must be zero.
} THREADNAME_INFO;
#pragma pack(pop)
void setWindowsThreadName(DWORD dwThreadID, const char* threadName) {
THREADNAME_INFO info;
info.dwType = 0x1000;
info.szName = threadName;
info.dwThreadID = dwThreadID;
info.dwFlags = 0;
#pragma warning(push)
#pragma warning(disable : 6320 6322)
__try {
RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info);
} __except (EXCEPTION_EXECUTE_HANDLER) {
}
#pragma warning(pop)
}
#endif
AtomicInt64 nextUnnamedThreadId{1};
// It is unsafe to access threadName before its dynamic initialization has completed. Use
// the execution of mongo initializers (which only happens once we have entered main, and
// therefore after dynamic initialization is complete) to signal that it is safe to use
// 'threadName'.
bool mongoInitializersHaveRun{};
MONGO_INITIALIZER(ThreadNameInitializer)(InitializerContext*) {
mongoInitializersHaveRun = true;
// The global initializers should only ever be run from main, so setting thread name
// here makes sense.
setThreadName("main");
return Status::OK();
}
thread_local std::string threadNameStorage;
} // namespace
namespace for_debuggers {
// This needs external linkage to ensure that debuggers can use it.
thread_local StringData threadName;
} // namespace for_debuggers
using for_debuggers::threadName;
void setThreadName(StringData name) {
invariant(mongoInitializersHaveRun);
threadNameStorage = name.toString();
threadName = threadNameStorage;
#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(), threadNameStorage.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 = threadNameStorage;
if (threadNameCopy.size() > MAXTHREADNAMESIZE) {
threadNameCopy.resize(MAXTHREADNAMESIZE - 4);
threadNameCopy += "...";
}
int error = pthread_setname_np(threadNameCopy.c_str());
if (error) {
log() << "Ignoring error from setting thread name: " << errnoWithDescription(error);
}
#elif defined(__linux__) && defined(MONGO_CONFIG_HAVE_PTHREAD_SETNAME_NP)
// 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) {
log() << "Ignoring error from setting thread name: " << errnoWithDescription(error);
}
}
#endif
}
StringData getThreadName() {
if (MONGO_unlikely(!mongoInitializersHaveRun)) {
// 'getThreadName' has been called before dynamic initialization for this
// translation unit has completed, so return a fallback value rather than accessing
// the 'threadName' variable, which requires dynamic initialization. We assume that
// we are in the 'main' thread.
static const std::string kFallback = "main";
return kFallback;
}
if (threadName.empty()) {
setThreadName(str::stream() << "thread" << nextUnnamedThreadId.fetchAndAdd(1));
}
return threadName;
}
} // namespace mongo