diff --git a/llvm/lib/Support/Windows/Threading.inc b/llvm/lib/Support/Windows/Threading.inc --- a/llvm/lib/Support/Windows/Threading.inc +++ b/llvm/lib/Support/Windows/Threading.inc @@ -60,7 +60,29 @@ uint32_t llvm::get_max_thread_name_length() { return 0; } #if defined(_MSC_VER) -static void SetThreadName(DWORD Id, LPCSTR Name) { +static void SetThreadName(DWORD Id, StringRef Name) { + // https://learn.microsoft.com/en-us/visualstudio/debugger/how-to-set-a-thread-name-in-native-code + + // Try first to use the modern SetThreadDescription API. + // This will work even if a debugger is not attached meaning that tools that + // don't use the debugger API can still query thread names. It's only + // available on Win10+. + typedef HRESULT(WINAPI * SetThreadDescriptionFn)(HANDLE hThread, + PCWSTR lpThreadDescription); + SetThreadDescriptionFn ProcSetThreadDescription = + (SetThreadDescriptionFn)GetProcAddress(GetModuleHandleW(L"Kernel32.dll"), + "SetThreadDescription"); + if (ProcSetThreadDescription) { + wchar_t NameWide[16] = {0}; + MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, Name.data(), -1, + NameWide, 16 - 1); + ProcSetThreadDescription(::GetCurrentThread(), NameWide); + return; + } + + // Fallback to throwing a specially-configured exception. This will only work + // if a debugger is attached - thread names will not be available in dumps or + // performance analysis tools. constexpr DWORD MS_VC_EXCEPTION = 0x406D1388; #pragma pack(push, 8) @@ -74,7 +96,7 @@ THREADNAME_INFO info; info.dwType = 0x1000; - info.szName = Name; + info.szName = Name.data(); info.dwThreadId = Id; info.dwFlags = 0; @@ -91,7 +113,7 @@ // Make sure the input is null terminated. SmallString<64> Storage; StringRef NameStr = Name.toNullTerminatedStringRef(Storage); - SetThreadName(::GetCurrentThreadId(), NameStr.data()); + SetThreadName(::GetCurrentThreadId(), NameStr); #endif }