From 516ce6b15c739ecaf5f2926f942e51970f87c4f0 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Tue, 8 Sep 2026 19:11:20 -0700 Subject: [PATCH] Threads: Support setting thread names through creation Gives the DiskCache a thread name so it's easier to find. --- FEXCore/Source/Interface/Core/DiskCache.cpp | 2 +- FEXCore/Source/Utils/Threads.cpp | 8 +++++--- FEXCore/Source/Utils/WorkQueueThread.cpp | 4 ++-- FEXCore/include/FEXCore/Utils/Threads.h | 4 ++-- .../include/FEXCore/Utils/WorkQueueThread.h | 2 +- .../LinuxSyscalls/Utils/Threads.cpp | 9 ++++++--- Source/Windows/Common/Threads.cpp | 18 +++++++++++++++--- 7 files changed, 32 insertions(+), 15 deletions(-) diff --git a/FEXCore/Source/Interface/Core/DiskCache.cpp b/FEXCore/Source/Interface/Core/DiskCache.cpp index 1ee8d6c52..b09eead30 100644 --- a/FEXCore/Source/Interface/Core/DiskCache.cpp +++ b/FEXCore/Source/Interface/Core/DiskCache.cpp @@ -459,7 +459,7 @@ namespace DiskCache { if (IsWritingDiskCache()) { FEXCore::Threads::Flags WriterThreadFlags = {.LowPriority = true, .Internal = true}; - Writer = fextl::make_unique(WriterThreadFlags); + Writer = fextl::make_unique(WriterThreadFlags, "FEX:DiskCache"); } } diff --git a/FEXCore/Source/Utils/Threads.cpp b/FEXCore/Source/Utils/Threads.cpp index 4b2ee9b74..7d0b98660 100644 --- a/FEXCore/Source/Utils/Threads.cpp +++ b/FEXCore/Source/Utils/Threads.cpp @@ -7,7 +7,8 @@ #include namespace FEXCore::Threads { -static fextl::unique_ptr CreateThread_Default(ThreadFunc Func, void* Arg, FEXCore::Threads::Flags Flags) { +static fextl::unique_ptr +CreateThread_Default(ThreadFunc Func, void* Arg, FEXCore::Threads::Flags Flags, const char* ThreadName) { ERROR_AND_DIE_FMT("Frontend didn't setup thread creation!"); } @@ -20,8 +21,9 @@ static FEXCore::Threads::Pointers Ptrs = { .CleanupAfterFork = CleanupAfterFork_Default, }; -fextl::unique_ptr FEXCore::Threads::Thread::Create(ThreadFunc Func, void* Arg, FEXCore::Threads::Flags Flags) { - return Ptrs.CreateThread(Func, Arg, Flags); +fextl::unique_ptr +FEXCore::Threads::Thread::Create(ThreadFunc Func, void* Arg, FEXCore::Threads::Flags Flags, const char* ThreadName) { + return Ptrs.CreateThread(Func, Arg, Flags, ThreadName); } void FEXCore::Threads::Thread::CleanupAfterFork() { diff --git a/FEXCore/Source/Utils/WorkQueueThread.cpp b/FEXCore/Source/Utils/WorkQueueThread.cpp index 710c87834..aba640818 100644 --- a/FEXCore/Source/Utils/WorkQueueThread.cpp +++ b/FEXCore/Source/Utils/WorkQueueThread.cpp @@ -4,8 +4,8 @@ namespace FEXCore { -WorkQueueThread::WorkQueueThread(FEXCore::Threads::Flags ThreadFlags) { - Thread = FEXCore::Threads::Thread::Create(ThreadEntry, this, ThreadFlags); +WorkQueueThread::WorkQueueThread(FEXCore::Threads::Flags ThreadFlags, const char* ThreadName) { + Thread = FEXCore::Threads::Thread::Create(ThreadEntry, this, ThreadFlags, ThreadName); } WorkQueueThread::~WorkQueueThread() { diff --git a/FEXCore/include/FEXCore/Utils/Threads.h b/FEXCore/include/FEXCore/Utils/Threads.h index 905c0c48a..c65dbebe3 100644 --- a/FEXCore/include/FEXCore/Utils/Threads.h +++ b/FEXCore/include/FEXCore/Utils/Threads.h @@ -13,7 +13,7 @@ struct Flags { using ThreadFunc = void* (*)(void* user_ptr); class Thread; -using CreateThreadFunc = fextl::unique_ptr (*)(ThreadFunc Func, void* Arg, Flags Flags); +using CreateThreadFunc = fextl::unique_ptr (*)(ThreadFunc Func, void* Arg, Flags Flags, const char* ThreadName); using CleanupAfterForkFunc = void (*)(); struct Pointers { @@ -34,7 +34,7 @@ public: * @name Calls provided API functions * @{ */ - static fextl::unique_ptr Create(ThreadFunc Func, void* Arg, Flags Flags = {}); + static fextl::unique_ptr Create(ThreadFunc Func, void* Arg, Flags Flags = {}, const char* ThreadName = nullptr); static void CleanupAfterFork(); diff --git a/FEXCore/include/FEXCore/Utils/WorkQueueThread.h b/FEXCore/include/FEXCore/Utils/WorkQueueThread.h index d33aad0b8..49a6da531 100644 --- a/FEXCore/include/FEXCore/Utils/WorkQueueThread.h +++ b/FEXCore/include/FEXCore/Utils/WorkQueueThread.h @@ -18,7 +18,7 @@ public: virtual void Run() = 0; }; - WorkQueueThread(FEXCore::Threads::Flags Flags = {}); + WorkQueueThread(FEXCore::Threads::Flags Flags = {}, const char* ThreadName = nullptr); ~WorkQueueThread(); void QueueWork(fextl::unique_ptr Work); diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/Utils/Threads.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/Utils/Threads.cpp index dd85c0d65..8b9c25948 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/Utils/Threads.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/Utils/Threads.cpp @@ -197,7 +197,7 @@ namespace PThreads { class PThread final : public FEXCore::Threads::Thread { public: - PThread(StackTracker* STracker, FEXCore::Threads::ThreadFunc Func, void* Arg, FEXCore::Threads::Flags Flags) + PThread(StackTracker* STracker, FEXCore::Threads::ThreadFunc Func, void* Arg, FEXCore::Threads::Flags Flags, const char* ThreadName) : STracker {STracker} , UserFunc {Func} , UserArg {Arg} @@ -226,6 +226,9 @@ namespace PThreads { HLE::ThreadManager::SetSignalMask(OldMask); } pthread_attr_destroy(&Attr); + if (ThreadName) { + pthread_setname_np(Thread, ThreadName); + } } bool joinable() override { @@ -375,8 +378,8 @@ namespace PThreads { static StackTracker* STracker {}; static fextl::unique_ptr - CreateThread_PThread(FEXCore::Threads::ThreadFunc Func, void* Arg, FEXCore::Threads::Flags Flags) { - return fextl::make_unique(STracker, Func, Arg, Flags); + CreateThread_PThread(FEXCore::Threads::ThreadFunc Func, void* Arg, FEXCore::Threads::Flags Flags, const char* ThreadName) { + return fextl::make_unique(STracker, Func, Arg, Flags, ThreadName); } static void CleanupAfterFork_PThread() { diff --git a/Source/Windows/Common/Threads.cpp b/Source/Windows/Common/Threads.cpp index 85b6b0b74..4247ac592 100644 --- a/Source/Windows/Common/Threads.cpp +++ b/Source/Windows/Common/Threads.cpp @@ -13,7 +13,7 @@ namespace FEX::Windows { namespace WinThreadImpl { class Thread final : public FEXCore::Threads::Thread { public: - Thread(FEXCore::Threads::ThreadFunc Func, void* Arg, FEXCore::Threads::Flags Flags) + Thread(FEXCore::Threads::ThreadFunc Func, void* Arg, FEXCore::Threads::Flags Flags, const char* ThreadName) : UserFunc {Func} , UserArg {Arg} , Flags {Flags} { @@ -28,6 +28,17 @@ namespace WinThreadImpl { LogMan::Msg::EFmt("NtCreateThreadEx failed: 0x{:x}", static_cast(Status)); Handle = nullptr; } + + if (ThreadName) { + UNICODE_STRING ThreadNameW; + if (RtlCreateUnicodeStringFromAsciiz(&ThreadNameW, ThreadName)) { + THREAD_NAME_INFORMATION info { + .ThreadName = ThreadNameW, + }; + NtSetInformationThread(Handle, static_cast(38) /* ThreadNameInformation */, &info, sizeof(info)); + RtlFreeUnicodeString(&ThreadNameW); + } + } } bool joinable() override { @@ -90,8 +101,9 @@ namespace WinThreadImpl { void* ReturnValue {}; }; - fextl::unique_ptr CreateThread(FEXCore::Threads::ThreadFunc Func, void* Arg, FEXCore::Threads::Flags Flags) { - return fextl::make_unique(Func, Arg, Flags); + fextl::unique_ptr + CreateThread(FEXCore::Threads::ThreadFunc Func, void* Arg, FEXCore::Threads::Flags Flags, const char* ThreadName) { + return fextl::make_unique(Func, Arg, Flags, ThreadName); } void CleanupAfterFork() {}