// Copyright (C) 2023 Jérôme "Lynix" Leclercq (lynix680@gmail.com) // This file is part of the "Nazara Engine - Core module" // For conditions of distribution and use, see copyright notice in Config.hpp #include #include #include #include namespace Nz::PlatformImpl { #ifndef NAZARA_COMPILER_MINGW namespace NAZARA_ANONYMOUS_NAMESPACE { // Windows 10, version 1607 added GetThreadDescription and SetThreadDescription in order to name a thread using GetThreadDescriptionFunc = HRESULT(WINAPI*)(HANDLE hThread, PWSTR* ppszThreadDescription); using SetThreadDescriptionFunc = HRESULT(WINAPI*)(HANDLE hThread, PCWSTR lpThreadDescription); #ifdef NAZARA_COMPILER_MSVC #pragma pack(push,8) struct THREADNAME_INFO { DWORD dwType; LPCSTR szName; DWORD dwThreadID; DWORD dwFlags; }; #pragma pack(pop) #endif // NAZARA_COMPILER_MSVC } #endif // !NAZARA_COMPILER_MINGW ThreadHandle GetCurrentThreadHandle() { #ifndef NAZARA_COMPILER_MINGW return ::GetCurrentThread(); #else return ::pthread_self(); #endif } std::string GetCurrentThreadName() { return GetThreadName(GetCurrentThreadHandle()); } std::string GetThreadName(ThreadHandle threadHandle) { NAZARA_USE_ANONYMOUS_NAMESPACE #ifndef NAZARA_COMPILER_MINGW // Use GetThreadDescription if available PWSTR namePtr; static GetThreadDescriptionFunc GetThreadDescription = reinterpret_cast(::GetProcAddress(::GetModuleHandleW(L"Kernel32.dll"), "GetThreadDescription")); if (!GetThreadDescription) return ""; HRESULT hr = GetThreadDescription(threadHandle, &namePtr); if (FAILED(hr)) return ""; CallOnExit freeName([&] { LocalFree(namePtr); }); return FromWideString(namePtr); #else std::array name; ::pthread_getname_np(threadHandle, &name[0], name.size()); return std::string(&name[0]); #endif } #ifndef NAZARA_COMPILER_MINGW void RaiseThreadNameException(DWORD threadId, const char* threadName) { #ifdef NAZARA_COMPILER_MSVC NAZARA_USE_ANONYMOUS_NAMESPACE if (!::IsDebuggerPresent()) return; // https://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx constexpr DWORD MS_VC_EXCEPTION = 0x406D1388; THREADNAME_INFO info; info.dwType = 0x1000; info.szName = threadName; info.dwThreadID = threadId; info.dwFlags = 0; #pragma warning(push) #pragma warning(disable: 6320 6322) __try { RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), reinterpret_cast(&info)); } __except (EXCEPTION_EXECUTE_HANDLER) { } #pragma warning(pop) #else NazaraWarning("ThreadName exception is only supported with MSVC"); #endif } #endif void SetCurrentThreadName(const char* threadName) { SetThreadName(GetCurrentThreadHandle(), threadName); } void SetThreadName(ThreadHandle threadHandle, const char* threadName) { #ifndef NAZARA_COMPILER_MINGW NAZARA_USE_ANONYMOUS_NAMESPACE // Try to use SetThreadDescription if available static SetThreadDescriptionFunc SetThreadDescription = reinterpret_cast(::GetProcAddress(::GetModuleHandleW(L"Kernel32.dll"), "SetThreadDescription")); if (SetThreadDescription) SetThreadDescription(threadHandle, ToWideString(threadName).data()); else RaiseThreadNameException(::GetThreadId(threadHandle), threadName); #else ::pthread_setname_np(threadHandle, threadName); #endif } } #ifndef NAZARA_COMPILER_MINGW #include #endif