Commit 1674ee82 authored by Orvid King's avatar Orvid King Committed by Facebook Github Bot

Support setThreadName on Windows

Summary: Windows doesn't have a nice function to do this, so we have to do it ourself, throwing the right exception with a struct that no public header defines, because Windows.

Reviewed By: akrieger

Differential Revision: D5100900

fbshipit-source-id: 4f6840e50c5c1aef36adade098739201c97b9af7
parent 511ddcc6
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <folly/Portability.h> #include <folly/Portability.h>
#include <folly/Traits.h> #include <folly/Traits.h>
#include <folly/portability/PThread.h> #include <folly/portability/PThread.h>
#include <folly/portability/Windows.h>
namespace folly { namespace folly {
...@@ -64,7 +65,7 @@ pthread_t stdTidToPthreadId(std::thread::id tid) { ...@@ -64,7 +65,7 @@ pthread_t stdTidToPthreadId(std::thread::id tid) {
bool canSetCurrentThreadName() { bool canSetCurrentThreadName() {
#if FOLLY_HAS_PTHREAD_SETNAME_NP_THREAD_NAME || \ #if FOLLY_HAS_PTHREAD_SETNAME_NP_THREAD_NAME || \
FOLLY_HAS_PTHREAD_SETNAME_NP_NAME FOLLY_HAS_PTHREAD_SETNAME_NP_NAME || _WIN32
return true; return true;
#else #else
return false; return false;
...@@ -72,7 +73,7 @@ bool canSetCurrentThreadName() { ...@@ -72,7 +73,7 @@ bool canSetCurrentThreadName() {
} }
bool canSetOtherThreadName() { bool canSetOtherThreadName() {
#if FOLLY_HAS_PTHREAD_SETNAME_NP_THREAD_NAME #if FOLLY_HAS_PTHREAD_SETNAME_NP_THREAD_NAME || _WIN32
return true; return true;
#else #else
return false; return false;
...@@ -90,6 +91,8 @@ Optional<std::string> getThreadName(std::thread::id id) { ...@@ -90,6 +91,8 @@ Optional<std::string> getThreadName(std::thread::id id) {
} }
return folly::make_optional(std::string(buf.data())); return folly::make_optional(std::string(buf.data()));
#else #else
// There's not actually a way to get the thread name on Windows because
// thread names are a concept managed by the debugger, not the runtime.
return Optional<std::string>(); return Optional<std::string>();
#endif #endif
} }
...@@ -99,8 +102,47 @@ Optional<std::string> getCurrentThreadName() { ...@@ -99,8 +102,47 @@ Optional<std::string> getCurrentThreadName() {
} }
bool setThreadName(std::thread::id tid, StringPiece name) { bool setThreadName(std::thread::id tid, StringPiece name) {
#if !FOLLY_HAVE_PTHREAD || _WIN32 auto trimmedName = name.subpiece(0, kMaxThreadNameLength - 1).str();
return false; #if _WIN32
static_assert(
sizeof(unsigned int) == sizeof(std::thread::id),
"This assumes std::thread::id is a thin wrapper around "
"the thread id as an unsigned int, but that doesn't appear to be true.");
// http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
#pragma pack(push, 8)
struct THREADNAME_INFO {
DWORD dwType; // Must be 0x1000
LPCSTR szName; // Pointer to name (in user address space)
DWORD dwThreadID; // Thread ID (-1 for caller thread)
DWORD dwFlags; // Reserved for future use; must be zero
};
union TNIUnion {
THREADNAME_INFO tni;
ULONG_PTR upArray[4];
};
#pragma pack(pop)
static constexpr DWORD kMSVCException = 0x406D1388;
// std::thread::id is a thin wrapper around an integral thread id,
// so just extract the ID.
unsigned int id;
std::memcpy(&id, &tid, sizeof(id));
TNIUnion tniUnion = {0x1000, trimmedName.data(), id, 0};
// This has to be in a separate stack frame from trimmedName, which requires
// C++ object destruction semantics.
return [&]() {
__try {
RaiseException(kMSVCException, 0, 4, tniUnion.upArray);
} __except (
GetExceptionCode() == kMSVCException ? EXCEPTION_CONTINUE_EXECUTION
: EXCEPTION_EXECUTE_HANDLER) {
// Swallow the exception when a debugger isn't attached.
}
return true;
}();
#else #else
name = name.subpiece(0, kMaxThreadNameLength - 1); name = name.subpiece(0, kMaxThreadNameLength - 1);
char buf[kMaxThreadNameLength] = {}; char buf[kMaxThreadNameLength] = {};
...@@ -125,8 +167,17 @@ bool setThreadName(std::thread::id tid, StringPiece name) { ...@@ -125,8 +167,17 @@ bool setThreadName(std::thread::id tid, StringPiece name) {
#if FOLLY_HAVE_PTHREAD #if FOLLY_HAVE_PTHREAD
bool setThreadName(pthread_t pid, StringPiece name) { bool setThreadName(pthread_t pid, StringPiece name) {
#if _WIN32 #if _WIN32
// Not currently supported on Windows. static_assert(
return false; sizeof(unsigned int) == sizeof(std::thread::id),
"This assumes std::thread::id is a thin wrapper around "
"the thread id as an unsigned int, but that doesn't appear to be true.");
// std::thread::id is a thin wrapper around an integral thread id,
// so just stick the ID in.
unsigned int tid = pthread_getw32threadid_np(pid);
std::thread::id id;
std::memcpy(&id, &tid, sizeof(id));
return setThreadName(id, name);
#else #else
static_assert( static_assert(
std::is_same<pthread_t, std::thread::native_handle_type>::value, std::is_same<pthread_t, std::thread::native_handle_type>::value,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment