NazaraEngine/src/Nazara/Core/Win32/ThreadImpl.cpp

136 lines
3.7 KiB
C++

// 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 <Nazara/Core/Win32/ThreadImpl.hpp>
#include <Nazara/Core/Format.hpp>
#include <Nazara/Core/StringExt.hpp>
#include <NazaraUtils/CallOnExit.hpp>
#include <Nazara/Core/Debug.hpp>
namespace Nz::PlatformImpl
{
#ifndef NAZARA_COMPILER_MINGW_THREADS_POSIX
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_THREADS_POSIX
return ::GetCurrentThread();
#else
return ::pthread_self();
#endif
}
std::string GetCurrentThreadName()
{
return GetThreadName(GetCurrentThreadHandle());
}
std::string GetThreadName(ThreadHandle threadHandle)
{
#ifndef NAZARA_COMPILER_MINGW_THREADS_POSIX
NAZARA_USE_ANONYMOUS_NAMESPACE
// Use GetThreadDescription if available
PWSTR namePtr;
static GetThreadDescriptionFunc GetThreadDescription = reinterpret_cast<GetThreadDescriptionFunc>(::GetProcAddress(::GetModuleHandleW(L"Kernel32.dll"), "GetThreadDescription"));
if (!GetThreadDescription)
return "<GetThreadDescription not supported>";
HRESULT hr = GetThreadDescription(threadHandle, &namePtr);
if (FAILED(hr))
return Format("<GetThreadDescription failed: {}>", HRESULT_CODE(hr));
CallOnExit freeName([&] { LocalFree(namePtr); });
return FromWideString(namePtr);
#else
std::array<char, 16> name;
::pthread_getname_np(threadHandle, &name[0], name.size());
return std::string(&name[0]);
#endif
}
#ifndef NAZARA_COMPILER_MINGW_THREADS_POSIX
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<ULONG_PTR*>(&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_THREADS_POSIX
NAZARA_USE_ANONYMOUS_NAMESPACE
// Try to use SetThreadDescription if available
static SetThreadDescriptionFunc SetThreadDescription = reinterpret_cast<SetThreadDescriptionFunc>(::GetProcAddress(::GetModuleHandleW(L"Kernel32.dll"), "SetThreadDescription"));
if (SetThreadDescription)
SetThreadDescription(threadHandle, ToWideString(threadName).data());
#if NAZARAUTILS_WINDOWS_NT6
else
RaiseThreadNameException(::GetThreadId(threadHandle), threadName);
#endif
#else
::pthread_setname_np(threadHandle, threadName);
#endif
}
}
#ifndef NAZARA_COMPILER_MINGW_THREADS_POSIX
#include <Nazara/Core/AntiWindows.hpp>
#endif