diff --git a/include/Nazara/Core/Thread.hpp b/include/Nazara/Core/Thread.hpp index a4b4d92f6..e129cbe40 100644 --- a/include/Nazara/Core/Thread.hpp +++ b/include/Nazara/Core/Thread.hpp @@ -32,11 +32,13 @@ namespace Nz Id GetId() const; bool IsJoinable() const; void Join(); + void SetName(const String& name); Thread& operator=(const Thread&) = delete; Thread& operator=(Thread&& thread); static unsigned int HardwareConcurrency(); + static void SetCurrentThreadName(const String& name); static void Sleep(UInt32 milliseconds); private: diff --git a/src/Nazara/Core/Posix/ThreadImpl.cpp b/src/Nazara/Core/Posix/ThreadImpl.cpp index b3948ee5d..aa0b87c5d 100644 --- a/src/Nazara/Core/Posix/ThreadImpl.cpp +++ b/src/Nazara/Core/Posix/ThreadImpl.cpp @@ -29,13 +29,22 @@ namespace Nz pthread_join(m_handle, nullptr); } - void* ThreadImpl::ThreadProc(void* userdata) + void ThreadImpl::SetName(const Nz::String& name) { - Functor* func = static_cast(userdata); - func->Run(); - delete func; +#ifdef __GNUC__ + pthread_setname_np(m_handle, name.GetConstBuffer()); +#else + NazaraWarning("Setting thread name is not supported on this platform"); +#endif + } - return nullptr; + void ThreadImpl::SetCurrentName(const Nz::String& name) + { +#ifdef __GNUC__ + pthread_setname_np(pthread_self(), name.GetConstBuffer()); +#else + NazaraWarning("Setting current thread name is not supported on this platform"); +#endif } void ThreadImpl::Sleep(UInt32 time) @@ -56,4 +65,13 @@ namespace Nz while (r == -1 && errno == EINTR); } } + + void* ThreadImpl::ThreadProc(void* userdata) + { + Functor* func = static_cast(userdata); + func->Run(); + delete func; + + return nullptr; + } } diff --git a/src/Nazara/Core/Posix/ThreadImpl.hpp b/src/Nazara/Core/Posix/ThreadImpl.hpp index 1ed6f3c8a..30d84d9d8 100644 --- a/src/Nazara/Core/Posix/ThreadImpl.hpp +++ b/src/Nazara/Core/Posix/ThreadImpl.hpp @@ -8,6 +8,11 @@ #define NAZARA_THREADIMPL_HPP #include + +#ifdef __GNUC__ +#define _GNU_SOURCE +#endif + #include namespace Nz @@ -21,7 +26,9 @@ namespace Nz void Detach(); void Join(); + void SetName(const Nz::String& name); + static void SetCurrentName(const Nz::String& name); static void Sleep(UInt32 time); private: diff --git a/src/Nazara/Core/Thread.cpp b/src/Nazara/Core/Thread.cpp index c9532ec19..d8b0ebd42 100644 --- a/src/Nazara/Core/Thread.cpp +++ b/src/Nazara/Core/Thread.cpp @@ -117,6 +117,25 @@ namespace Nz m_impl = nullptr; } + /*! + * \brief Changes the debugging name associated to a thread + * + * Changes the debugging name associated with a particular thread, and may helps with debugging tools. + * + * \param name The new name of the thread + * + * \remark Due to system limitations, thread name cannot exceed 15 characters (excluding null-terminator) + * + * \see SetCurrentThreadName + */ + void Thread::SetName(const String& name) + { + NazaraAssert(m_impl, "Invalid thread"); + NazaraAssert(name.GetSize() < 16, "Thread name is too long"); + + m_impl->SetName(name); + } + /*! * \brief Moves the other thread into this * \return A reference to this @@ -145,18 +164,35 @@ namespace Nz * \brief Gets the number of simulatenous threads that can run on the same cpu * \return The number of simulatenous threads */ - unsigned int Thread::HardwareConcurrency() { return HardwareInfo::GetProcessorCount(); } + + /*! + * \brief Changes the debugging name associated to the calling thread + * + * Changes the debugging name associated with the calling thread, and may helps with debugging tools. + * + * \param name The new name associated with this thread + * + * \remark Due to system limitations, thread name cannot exceed 15 characters (excluding null-terminator) + * + * \see SetName + */ + void Thread::SetCurrentThreadName(const String& name) + { + NazaraAssert(name.GetSize() < 16, "Thread name is too long"); + + ThreadImpl::SetCurrentName(name); + } + /*! * \brief Makes sleep this thread * * \param milliseconds The number of milliseconds to sleep */ - void Thread::Sleep(UInt32 milliseconds) { ThreadImpl::Sleep(milliseconds); diff --git a/src/Nazara/Core/Win32/ThreadImpl.cpp b/src/Nazara/Core/Win32/ThreadImpl.cpp index 5b44b94b6..e59413413 100644 --- a/src/Nazara/Core/Win32/ThreadImpl.cpp +++ b/src/Nazara/Core/Win32/ThreadImpl.cpp @@ -6,13 +6,27 @@ #include #include #include +#include #include namespace Nz { + namespace + { +#pragma pack(push,8) + struct THREADNAME_INFO + { + DWORD dwType; + LPCSTR szName; + DWORD dwThreadID; + DWORD dwFlags; + }; +#pragma pack(pop) + } + ThreadImpl::ThreadImpl(Functor* functor) { - m_handle = reinterpret_cast(_beginthreadex(nullptr, 0, &ThreadImpl::ThreadProc, functor, 0, nullptr)); + m_handle = reinterpret_cast(_beginthreadex(nullptr, 0, &ThreadImpl::ThreadProc, functor, 0, &m_threadId)); if (!m_handle) NazaraInternalError("Failed to create thread: " + Error::GetLastSystemError()); } @@ -29,6 +43,44 @@ namespace Nz CloseHandle(m_handle); } + void ThreadImpl::SetName(const Nz::String& name) + { + SetThreadName(m_threadId, name.GetConstBuffer()); + } + + void ThreadImpl::SetCurrentName(const Nz::String& name) + { + SetThreadName(::GetCurrentThreadId(), name.GetConstBuffer()); + } + + void ThreadImpl::Sleep(UInt32 time) + { + ::Sleep(time); + } + + void ThreadImpl::SetThreadName(DWORD threadId, const char* threadName) + { + // 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) + } + unsigned int __stdcall ThreadImpl::ThreadProc(void* userdata) { Functor* func = static_cast(userdata); @@ -42,9 +94,4 @@ namespace Nz return 0; } - - void ThreadImpl::Sleep(UInt32 time) - { - ::Sleep(time); - } } diff --git a/src/Nazara/Core/Win32/ThreadImpl.hpp b/src/Nazara/Core/Win32/ThreadImpl.hpp index 12e7f5c14..8070f7a22 100644 --- a/src/Nazara/Core/Win32/ThreadImpl.hpp +++ b/src/Nazara/Core/Win32/ThreadImpl.hpp @@ -10,6 +10,7 @@ #define NAZARA_THREADIMPL_HPP #include +#include #include namespace Nz @@ -23,12 +24,16 @@ namespace Nz void Detach(); void Join(); + void SetName(const Nz::String& name); + static void SetCurrentName(const Nz::String& name); static void Sleep(UInt32 time); private: + static void SetThreadName(DWORD threadId, const char* threadName); static unsigned int __stdcall ThreadProc(void* userdata); + DWORD m_threadId; HANDLE m_handle; }; }