From c73d08af9b7c7755bdfbba76fa9998d5e8cec372 Mon Sep 17 00:00:00 2001 From: Lynix Date: Mon, 6 Jan 2020 15:35:48 +0100 Subject: [PATCH] Core/Thread: Make use of SetThreadDescription if possible (win32) --- ChangeLog.md | 1 + src/Nazara/Core/Win32/ThreadImpl.cpp | 36 ++++++++++++++++++++-------- src/Nazara/Core/Win32/ThreadImpl.hpp | 3 ++- 3 files changed, 29 insertions(+), 11 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index b5c69575d..ad7c63e81 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -215,6 +215,7 @@ Nazara Engine: - Added EmptyStream class, useful to measure how many bytes some writing operations will take - SegmentCollider2D: Add support for neighbors (aka "ghost vertices"), allowing to prevent seams collisions - ⚠ OBJLoader flips UV by default, fixing a lot of models UV +- On Windows, Thread::Set(Current)Name now uses `SetThreadDescription` Win32 function if possible instead of triggering a debugger exception. MinGW builds will use this if available too. Nazara Development Kit: - Added ImageWidget (#139) diff --git a/src/Nazara/Core/Win32/ThreadImpl.cpp b/src/Nazara/Core/Win32/ThreadImpl.cpp index 4dd557536..0ad2293cc 100644 --- a/src/Nazara/Core/Win32/ThreadImpl.cpp +++ b/src/Nazara/Core/Win32/ThreadImpl.cpp @@ -11,6 +11,9 @@ namespace Nz { + // Windows 10, version 1607 brought SetThreadDescription in order to name a thread + using SetThreadDescriptionFunc = HRESULT(WINAPI*)(HANDLE hThread, PCWSTR lpThreadDescription); + #ifdef NAZARA_COMPILER_MSVC namespace { @@ -50,12 +53,12 @@ namespace Nz void ThreadImpl::SetName(const Nz::String& name) { - SetThreadName(m_threadId, name.GetConstBuffer()); + SetThreadName(m_handle, name); } void ThreadImpl::SetCurrentName(const Nz::String& name) { - SetThreadName(::GetCurrentThreadId(), name.GetConstBuffer()); + SetThreadName(::GetCurrentThread(), name); } void ThreadImpl::Sleep(UInt32 time) @@ -63,9 +66,12 @@ namespace Nz ::Sleep(time); } - void ThreadImpl::SetThreadName(DWORD threadId, const char* threadName) + void ThreadImpl::RaiseThreadNameException(DWORD threadId, const char* threadName) { - #ifdef NAZARA_COMPILER_MSVC +#ifdef NAZARA_COMPILER_MSVC + if (!::IsDebuggerPresent()) + return; + // https://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx constexpr DWORD MS_VC_EXCEPTION = 0x406D1388; @@ -75,8 +81,8 @@ namespace Nz info.dwThreadID = threadId; info.dwFlags = 0; - #pragma warning(push) - #pragma warning(disable: 6320 6322) +#pragma warning(push) +#pragma warning(disable: 6320 6322) __try { RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), reinterpret_cast(&info)); @@ -84,10 +90,20 @@ namespace Nz __except (EXCEPTION_EXECUTE_HANDLER) { } - #pragma warning(pop) - #else - NazaraWarning("SetThreadName on Windows is only supported with MSVC for now"); - #endif +#pragma warning(pop) +#else + NazaraWarning("SetThreadDescription is not supported and threadname exception is only supported with MSVC"); +#endif + } + + void ThreadImpl::SetThreadName(HANDLE threadHandle, const Nz::String& name) + { + // Try to use SetThreadDescription if available + static SetThreadDescriptionFunc SetThreadDescription = reinterpret_cast(::GetProcAddress(::GetModuleHandleW(L"Kernel32.dll"), "SetThreadDescription")); + if (SetThreadDescription) + SetThreadDescription(threadHandle, name.GetWideString().data()); + else + RaiseThreadNameException(::GetThreadId(threadHandle), name.GetConstBuffer()); } unsigned int __stdcall ThreadImpl::ThreadProc(void* userdata) diff --git a/src/Nazara/Core/Win32/ThreadImpl.hpp b/src/Nazara/Core/Win32/ThreadImpl.hpp index 8bc25930d..c12697611 100644 --- a/src/Nazara/Core/Win32/ThreadImpl.hpp +++ b/src/Nazara/Core/Win32/ThreadImpl.hpp @@ -30,7 +30,8 @@ namespace Nz static void Sleep(UInt32 time); private: - static void SetThreadName(DWORD threadId, const char* threadName); + static void RaiseThreadNameException(DWORD threadId, const char* threadName); + static void SetThreadName(HANDLE threadHandle, const Nz::String& name); static unsigned int __stdcall ThreadProc(void* userdata); DWORD m_threadId;