// SPDX-License-Identifier: MIT #include "Threads.h" #include "CRT/CRT.h" #include #include #include #include #include namespace FEX::Windows { namespace WinThreadImpl { class Thread final : public FEXCore::Threads::Thread { public: Thread(FEXCore::Threads::ThreadFunc Func, void* Arg) : UserFunc {Func} , UserArg {Arg} { // hide everything from guest, don't initialize anything, we'll do that manually in RunThread() const ULONG CreateFlags = THREAD_CREATE_FLAGS_SKIP_THREAD_ATTACH | THREAD_CREATE_FLAGS_HIDE_FROM_DEBUGGER | THREAD_CREATE_FLAGS_SKIP_LOADER_INIT | THREAD_CREATE_FLAGS_BYPASS_PROCESS_FREEZE; NTSTATUS Status = NtCreateThreadEx(&Handle, THREAD_ALL_ACCESS, nullptr, GetCurrentProcess(), reinterpret_cast(&Thread::RunThread), this, CreateFlags, 0, 0, 0, nullptr); if (Status < 0) { LogMan::Msg::EFmt("NtCreateThreadEx failed: 0x{:x}", static_cast(Status)); Handle = nullptr; } } bool joinable() override { return Handle != nullptr; } bool join(void** ret) override { if (!Handle) { return false; } NtWaitForSingleObject(Handle, FALSE, nullptr); if (ret) { *ret = ReturnValue; } return true; } bool detach() override { // almost no-op, it's already detached, just deref handle if (Handle) { NtClose(Handle); Handle = nullptr; } return true; } bool IsSelf() override { return TID == GetCurrentThreadId(); } ~Thread() override { if (Handle) { NtClose(Handle); } } private: static void RunThread(Thread* This) { This->TID = GetCurrentThreadId(); // do initialization we skipped earlier here around the user entrypoint FEX::Windows::InitCRTThread(); This->ReturnValue = This->UserFunc(This->UserArg); FEX::Windows::DeinitCRTThread(); NtTerminateThread(GetCurrentThread(), 0); } FEXCore::Threads::ThreadFunc UserFunc; void* UserArg; HANDLE Handle {}; DWORD TID {}; void* ReturnValue {}; }; fextl::unique_ptr CreateThread(FEXCore::Threads::ThreadFunc Func, void* Arg) { return fextl::make_unique(Func, Arg); } void CleanupAfterFork() {} } // namespace WinThreadImpl void SetupThreadHandlers() { FEXCore::Threads::Pointers Ptrs = { .CreateThread = WinThreadImpl::CreateThread, .CleanupAfterFork = WinThreadImpl::CleanupAfterFork, }; FEXCore::Threads::Thread::SetInternalPointers(Ptrs); } } // namespace FEX::Windows