Skip to content

Instantly share code, notes, and snippets.

@mildsunrise
Last active May 2, 2022 15:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mildsunrise/c33c2e27c06e655aa0ad69210da09a74 to your computer and use it in GitHub Desktop.
Save mildsunrise/c33c2e27c06e655aa0ad69210da09a74 to your computer and use it in GitHub Desktop.
Portable way to set current thread's name (C++11 or later)
// Definition of a SetThreadName function with an emphasis in "portability",
// meaning we prefer cautiously failing over creating build errors (or crashes)
// on exotic platforms. To do this, we only include/link against very
// few & widely available symbols.
#include "thread_name.h"
#if defined(__linux__)
// For Linux use the prctl API directly. prctl symbol
// should be available under any libc.
#include <sys/prctl.h>
// Define here to avoid relying on kernel headers being present
#define PR_SET_NAME 15 /* Set process name */
bool SetThreadName(const char* name) {
return prctl(PR_SET_NAME, name, 0, 0, 0) >= 0;
}
#elif defined(__APPLE__)
// For MacOS use the dynamic linker because I don't
// want to take any risks
#include <dlfcn.h>
extern "C" typedef int (*SetNameFn)(const char*);
bool SetThreadName(const char* name) {
auto pthread_setname_np = reinterpret_cast<SetNameFn>(
dlsym(RTLD_DEFAULT, "pthread_setname_np"));
if (pthread_setname_np == nullptr)
return false;
return pthread_setname_np(name) == 0;
}
#elif defined(_WIN32)
// For Windows, we use the new SetThreadDescription API which
// is only available in newish versions. To avoid taking any
// risks (and because on certain versions it's the only
// option to access the API), we use the dynamic linker
#include <windows.h>
extern "C" typedef HRESULT (WINAPI *SetThreadDescriptionFn)(HANDLE, PCWSTR);
static SetThreadDescriptionFn RetrieveSymbol(const char* objectName) {
auto mod = GetModuleHandleA(objectName);
if (mod == nullptr) return nullptr;
auto symbol = GetProcAddress(mod, "SetThreadDescription");
return reinterpret_cast<SetThreadDescriptionFn>(symbol);
}
#include <locale>
#include <codecvt>
#include <string>
bool SetThreadName(const char* name) {
auto SetThreadDescription = RetrieveSymbol("Kernel32.dll");
// apparently, MSDN is wrong and the symbol is defined in
// KernelBase.dll, so try that too
if (SetThreadDescription == nullptr)
SetThreadDescription = RetrieveSymbol("KernelBase.dll");
if (SetThreadDescription == nullptr) return false;
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
std::wstring wide_name = converter.from_bytes(name);
auto result = SetThreadDescription(GetCurrentThread(), wide_name.c_str());
return SUCCEEDED(result);
}
#else
bool SetThreadName(const char* name) {
return false;
}
#endif
/**
* Sets the name of the calling thread to `name`, which is
* a NUL terminated UTF-8 string. Returns true if success,
* false if error or unsupported platform.
*
* Since this is an OS-dependent operation, the requirements
* of `name` may vary depending on platform. For example on
* Linux, the maximum length (excluding the terminator) is
* 16 bytes, and UTF-8 isn't strictly required (only conventional).
*/
bool SetThreadName(const char* name);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment