From 8214b8c8d1dd0f1a0b37c2775adae88d0058d114 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Thu, 22 Aug 2024 16:35:45 -0700 Subject: [PATCH] SignalDelegator: Refactor how thread local data is stored Two primary things here: - Remove the static `GlobalDelegator` - Move the thread_local SignalDelegator::ThreadState information directly in to ThreadStateObject Having the ThreadStateObject and the SignalDelegator information disjoint was confusing but was required when we didn't have any object in the frontend that could have its own independent data. Since we fixed this with the `ThreadStateObject` type we can now move this over. The `GlobalDelegator` object is now instead stored in `ThreadStateObject` instead. Instead of using a thread_local variable, we now just consume 8-bytes of the signal alt-stack since the kernel gives us that information about where it lives. This then converts all the thread_local usage to use either the passed in CPU state if it exists, or fetching it from the alt-stack offset. Very minor changes in behaviour here, will help when trying to improve FEX's behaviour around signals. --- .../LinuxSyscalls/SignalDelegator.cpp | 139 ++++++++---------- .../LinuxSyscalls/SignalDelegator.h | 14 +- .../LinuxSyscalls/Syscalls/Signals.cpp | 9 +- .../LinuxSyscalls/ThreadManager.h | 24 +++ .../LinuxEmulation/LinuxSyscalls/x32/FS.cpp | 3 +- .../LinuxSyscalls/x32/Signals.cpp | 10 +- .../LinuxSyscalls/x32/Thread.cpp | 3 +- .../LinuxSyscalls/x64/Thread.cpp | 3 +- 8 files changed, 107 insertions(+), 98 deletions(-) diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/SignalDelegator.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/SignalDelegator.cpp index 8d6fa75987..2bbb53bbe8 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/SignalDelegator.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/SignalDelegator.cpp @@ -49,30 +49,17 @@ __attribute__((naked)) static void sigrestore() { constexpr static uint32_t X86_MINSIGSTKSZ = 0x2000U; -// We can only have one delegator per process -static SignalDelegator* GlobalDelegator {}; - -struct ThreadState { - FEX::HLE::ThreadStateObject* Thread {}; - - void* AltStackPtr {}; - stack_t GuestAltStack { - .ss_sp = nullptr, - .ss_flags = SS_DISABLE, // By default the guest alt stack is disabled - .ss_size = 0, - }; - // This is the thread's current signal mask - GuestSAMask CurrentSignalMask {}; - // The mask prior to a suspend - GuestSAMask PreviousSuspendMask {}; - - uint64_t PendingSignals {}; -}; - -thread_local ThreadState ThreadData {}; +static FEX::HLE::ThreadStateObject* GetThreadFromAltStack(const stack_t& alt_stack) { + // The thread object lives just before the alt-stack begin. + FEX::HLE::ThreadStateObject* ThreadObject {}; + memcpy(&ThreadObject, reinterpret_cast(reinterpret_cast(alt_stack.ss_sp) - 8), sizeof(void*)); + return ThreadObject; +} static void SignalHandlerThunk(int Signal, siginfo_t* Info, void* UContext) { - GlobalDelegator->HandleSignal(Signal, Info, UContext); + ucontext_t* _context = (ucontext_t*)UContext; + auto ThreadObject = GetThreadFromAltStack(_context->uc_stack); + ThreadObject->SignalInfo.Delegator->HandleSignal(ThreadObject, Signal, Info, UContext); } uint64_t SigIsMember(GuestSAMask* Set, int Signal) { @@ -137,10 +124,8 @@ static SigInfoLayout CalculateSigInfoLayout(int Signal, int si_code) { return SigInfoLayout::LAYOUT_KILL; } -void SignalDelegator::HandleSignal(int Signal, void* Info, void* UContext) { +void SignalDelegator::HandleSignal(FEX::HLE::ThreadStateObject* Thread, int Signal, void* Info, void* UContext) { // Let the host take first stab at handling the signal - auto Thread = GetTLSThread(); - if (!Thread) { LogMan::Msg::AFmt("[{}] Thread has received a signal and hasn't registered itself with the delegate! Programming error!", FHU::Syscalls::gettid()); @@ -159,7 +144,7 @@ void SignalDelegator::HandleSignal(int Signal, void* Info, void* UContext) { // Now let the frontend handle the signal // It's clearly a guest signal and this ends up being an OS specific issue - HandleGuestSignal(Thread->Thread, Signal, Info, UContext); + HandleGuestSignal(Thread, Signal, Info, UContext); } } @@ -1332,7 +1317,8 @@ static bool IsAsyncSignal(const siginfo_t* Info, int Signal) { return true; } -void SignalDelegator::HandleGuestSignal(FEXCore::Core::InternalThreadState* Thread, int Signal, void* Info, void* UContext) { +void SignalDelegator::HandleGuestSignal(FEX::HLE::ThreadStateObject* ThreadObject, int Signal, void* Info, void* UContext) { + auto Thread = ThreadObject->Thread; ucontext_t* _context = (ucontext_t*)UContext; auto SigInfo = *static_cast(Info); @@ -1413,10 +1399,10 @@ void SignalDelegator::HandleGuestSignal(FEXCore::Core::InternalThreadState* Thre } // Check for masked signals - if (ThreadData.CurrentSignalMask.Val & (1ULL << (Signal - 1)) && IsAsyncSignal(&SigInfo, Signal)) { + if (ThreadObject->SignalInfo.CurrentSignalMask.Val & (1ULL << (Signal - 1)) && IsAsyncSignal(&SigInfo, Signal)) { // This signal is masked, must defer until the guest updates the signal mask. // Add it to the pending signal list - ThreadData.PendingSignals |= 1ULL << (Signal - 1); + ThreadObject->SignalInfo.PendingSignals |= 1ULL << (Signal - 1); return; } @@ -1424,7 +1410,7 @@ void SignalDelegator::HandleGuestSignal(FEXCore::Core::InternalThreadState* Thre SignalHandler& Handler = HostHandlers[Signal]; // Remove the pending signal - ThreadData.PendingSignals &= ~(1ULL << (Signal - 1)); + ThreadObject->SignalInfo.PendingSignals &= ~(1ULL << (Signal - 1)); // We have an emulation thread pointer, we can now modify its state if (Handler.GuestAction.sigaction_handler.handler == SIG_DFL) { @@ -1435,7 +1421,8 @@ void SignalDelegator::HandleGuestSignal(FEXCore::Core::InternalThreadState* Thre } else if (Handler.GuestAction.sigaction_handler.handler == SIG_IGN) { return; } else { - if (Handler.GuestHandler && Handler.GuestHandler(Thread, Signal, &SigInfo, UContext, &Handler.GuestAction, &ThreadData.GuestAltStack)) { + if (Handler.GuestHandler && + Handler.GuestHandler(Thread, Signal, &SigInfo, UContext, &Handler.GuestAction, &ThreadObject->SignalInfo.GuestAltStack)) { // Set up a new mask based on this signals signal mask uint64_t NewMask = Handler.GuestAction.sa_mask.Val; @@ -1598,9 +1585,6 @@ void SignalDelegator::UninstallHostHandler(int Signal) { SignalDelegator::SignalDelegator(FEXCore::Context::Context* _CTX, const std::string_view ApplicationName) : CTX {_CTX} , ApplicationName {ApplicationName} { - // Register this delegate - LOGMAN_THROW_AA_FMT(!GlobalDelegator, "Can't register global delegator multiple times!"); - GlobalDelegator = this; // Signal zero isn't real HostHandlers[0].Installed = true; @@ -1654,7 +1638,7 @@ SignalDelegator::SignalDelegator(FEXCore::Context::Context* _CTX, const std::str if (PC == reinterpret_cast(&FEXCore::Assert::ForcedAssert)) { // This is a host side assert. Don't deliver this to the guest // We want to actually break here - GlobalDelegator->UninstallHostHandler(Signal); + FEX::HLE::ThreadManager::GetStateObjectFromFEXCoreThread(Thread)->SignalInfo.Delegator->UninstallHostHandler(Signal); return true; } return false; @@ -1662,16 +1646,17 @@ SignalDelegator::SignalDelegator(FEXCore::Context::Context* _CTX, const std::str true); const auto PauseHandler = [](FEXCore::Core::InternalThreadState* Thread, int Signal, void* info, void* ucontext) -> bool { - return GlobalDelegator->HandleSignalPause(Thread, Signal, info, ucontext); + return FEX::HLE::ThreadManager::GetStateObjectFromFEXCoreThread(Thread)->SignalInfo.Delegator->HandleSignalPause(Thread, Signal, info, ucontext); }; const auto GuestSignalHandler = [](FEXCore::Core::InternalThreadState* Thread, int Signal, void* info, void* ucontext, GuestSigAction* GuestAction, stack_t* GuestStack) -> bool { - return GlobalDelegator->HandleDispatcherGuestSignal(Thread, Signal, info, ucontext, GuestAction, GuestStack); + return FEX::HLE::ThreadManager::GetStateObjectFromFEXCoreThread(Thread)->SignalInfo.Delegator->HandleDispatcherGuestSignal( + Thread, Signal, info, ucontext, GuestAction, GuestStack); }; const auto SigillHandler = [](FEXCore::Core::InternalThreadState* Thread, int Signal, void* info, void* ucontext) -> bool { - return GlobalDelegator->HandleSIGILL(Thread, Signal, info, ucontext); + return FEX::HLE::ThreadManager::GetStateObjectFromFEXCoreThread(Thread)->SignalInfo.Delegator->HandleSIGILL(Thread, Signal, info, ucontext); }; // Register SIGILL signal handler. @@ -1692,7 +1677,8 @@ SignalDelegator::SignalDelegator(FEXCore::Context::Context* _CTX, const std::str return false; } - const auto Result = FEXCore::ArchHelpers::Arm64::HandleUnalignedAccess(Thread, GlobalDelegator->GetUnalignedHandlerType(), PC, + const auto Delegator = FEX::HLE::ThreadManager::GetStateObjectFromFEXCoreThread(Thread)->SignalInfo.Delegator; + const auto Result = FEXCore::ArchHelpers::Arm64::HandleUnalignedAccess(Thread, Delegator->GetUnalignedHandlerType(), PC, ArchHelpers::Context::GetArmGPRs(ucontext)); ArchHelpers::Context::SetPc(ucontext, PC + Result.second); return Result.first; @@ -1717,25 +1703,23 @@ SignalDelegator::~SignalDelegator() { ::syscall(SYS_rt_sigaction, i, &HostHandlers[i].OldAction, nullptr, 8); HostHandlers[i].Installed = false; } - GlobalDelegator = nullptr; -} - -FEX::HLE::ThreadStateObject* SignalDelegator::GetTLSThread() { - return ThreadData.Thread; } void SignalDelegator::RegisterTLSState(FEX::HLE::ThreadStateObject* Thread) { - ThreadData.Thread = Thread; + Thread->SignalInfo.Delegator = this; // Set up our signal alternative stack // This is per thread rather than per signal - ThreadData.AltStackPtr = FEXCore::Allocator::mmap(nullptr, SIGSTKSZ * 16, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + Thread->SignalInfo.AltStackPtr = FEXCore::Allocator::mmap(nullptr, SIGSTKSZ * 16, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); stack_t altstack {}; - altstack.ss_sp = ThreadData.AltStackPtr; - altstack.ss_size = SIGSTKSZ * 16; + altstack.ss_sp = reinterpret_cast(reinterpret_cast(Thread->SignalInfo.AltStackPtr) + 8); + altstack.ss_size = SIGSTKSZ * 16 - 8; altstack.ss_flags = 0; LOGMAN_THROW_AA_FMT(!!altstack.ss_sp, "Couldn't allocate stack pointer"); + // Copy the thread object to the start of the alt-stack + memcpy(Thread->SignalInfo.AltStackPtr, &Thread, sizeof(void*)); + // Register the alt stack const int Result = sigaltstack(&altstack, nullptr); if (Result == -1) { @@ -1743,7 +1727,7 @@ void SignalDelegator::RegisterTLSState(FEX::HLE::ThreadStateObject* Thread) { } // Get the current host signal mask - ::syscall(SYS_rt_sigprocmask, 0, nullptr, &ThreadData.CurrentSignalMask.Val, 8); + ::syscall(SYS_rt_sigprocmask, 0, nullptr, &Thread->SignalInfo.CurrentSignalMask.Val, 8); if (Thread->Thread) { // Reserve a small amount of deferred signal frames. Usually the stack won't be utilized beyond @@ -1753,9 +1737,9 @@ void SignalDelegator::RegisterTLSState(FEX::HLE::ThreadStateObject* Thread) { } void SignalDelegator::UninstallTLSState(FEX::HLE::ThreadStateObject* Thread) { - FEXCore::Allocator::munmap(ThreadData.AltStackPtr, SIGSTKSZ * 16); + FEXCore::Allocator::munmap(Thread->SignalInfo.AltStackPtr, SIGSTKSZ * 16); - ThreadData.AltStackPtr = nullptr; + Thread->SignalInfo.AltStackPtr = nullptr; stack_t altstack {}; altstack.ss_flags = SS_DISABLE; @@ -1765,8 +1749,6 @@ void SignalDelegator::UninstallTLSState(FEX::HLE::ThreadStateObject* Thread) { if (Result == -1) { LogMan::Msg::EFmt("Failed to uninstall alternative signal stack {}", strerror(errno)); } - - ThreadData.Thread = nullptr; } void SignalDelegator::FrontendRegisterHostSignalHandler(int Signal, HostSignalDelegatorFunction Func, bool Required) { @@ -1850,20 +1832,19 @@ void SignalDelegator::CheckXIDHandler() { } } -uint64_t SignalDelegator::RegisterGuestSigAltStack(const stack_t* ss, stack_t* old_ss) { - auto Thread = GetTLSThread(); +uint64_t SignalDelegator::RegisterGuestSigAltStack(FEX::HLE::ThreadStateObject* Thread, const stack_t* ss, stack_t* old_ss) { bool UsingAltStack {}; - uint64_t AltStackBase = reinterpret_cast(ThreadData.GuestAltStack.ss_sp); - uint64_t AltStackEnd = AltStackBase + ThreadData.GuestAltStack.ss_size; + uint64_t AltStackBase = reinterpret_cast(Thread->SignalInfo.GuestAltStack.ss_sp); + uint64_t AltStackEnd = AltStackBase + Thread->SignalInfo.GuestAltStack.ss_size; uint64_t GuestSP = Thread->Thread->CurrentFrame->State.gregs[FEXCore::X86State::REG_RSP]; - if (!(ThreadData.GuestAltStack.ss_flags & SS_DISABLE) && GuestSP >= AltStackBase && GuestSP <= AltStackEnd) { + if (!(Thread->SignalInfo.GuestAltStack.ss_flags & SS_DISABLE) && GuestSP >= AltStackBase && GuestSP <= AltStackEnd) { UsingAltStack = true; } // If we have an old signal set then give it back if (old_ss) { - *old_ss = ThreadData.GuestAltStack; + *old_ss = Thread->SignalInfo.GuestAltStack; if (UsingAltStack) { // We are currently operating on the alt stack @@ -1891,7 +1872,7 @@ uint64_t SignalDelegator::RegisterGuestSigAltStack(const stack_t* ss, stack_t* o if (ss->ss_flags & SS_DISABLE) { // If SS_DISABLE Is specified then the rest of the details are ignored - ThreadData.GuestAltStack = *ss; + Thread->SignalInfo.GuestAltStack = *ss; return 0; } @@ -1900,28 +1881,26 @@ uint64_t SignalDelegator::RegisterGuestSigAltStack(const stack_t* ss, stack_t* o return -ENOMEM; } - ThreadData.GuestAltStack = *ss; + Thread->SignalInfo.GuestAltStack = *ss; } return 0; } -static void CheckForPendingSignals(FEXCore::Core::InternalThreadState* Thread) { - auto ThreadObject = static_cast(Thread->FrontendPtr); - +static void CheckForPendingSignals(const FEX::HLE::ThreadStateObject* Thread) { // Do we have any pending signals that became unmasked? - uint64_t PendingSignals = ~ThreadData.CurrentSignalMask.Val & ThreadData.PendingSignals; + uint64_t PendingSignals = ~Thread->SignalInfo.CurrentSignalMask.Val & Thread->SignalInfo.PendingSignals; if (PendingSignals != 0) { for (int i = 0; i < 64; ++i) { if (PendingSignals & (1ULL << i)) { - FHU::Syscalls::tgkill(ThreadObject->ThreadInfo.PID, ThreadObject->ThreadInfo.TID, i + 1); + FHU::Syscalls::tgkill(Thread->ThreadInfo.PID, Thread->ThreadInfo.TID, i + 1); // We might not even return here which is spooky } } } } -uint64_t SignalDelegator::GuestSigProcMask(int how, const uint64_t* set, uint64_t* oldset) { +uint64_t SignalDelegator::GuestSigProcMask(FEX::HLE::ThreadStateObject* Thread, int how, const uint64_t* set, uint64_t* oldset) { // The order in which we handle signal mask setting is important here // old and new can point to the same location in memory. // Even if the pointers are to same memory location, we must store the original signal mask @@ -1929,21 +1908,21 @@ uint64_t SignalDelegator::GuestSigProcMask(int how, const uint64_t* set, uint64_ // 1) Store old mask // 2) Set mask to new mask if exists // 3) Give old mask back - auto OldSet = ThreadData.CurrentSignalMask.Val; + auto OldSet = Thread->SignalInfo.CurrentSignalMask.Val; if (!!set) { uint64_t IgnoredSignalsMask = ~((1ULL << (SIGKILL - 1)) | (1ULL << (SIGSTOP - 1))); if (how == SIG_BLOCK) { - ThreadData.CurrentSignalMask.Val |= *set & IgnoredSignalsMask; + Thread->SignalInfo.CurrentSignalMask.Val |= *set & IgnoredSignalsMask; } else if (how == SIG_UNBLOCK) { - ThreadData.CurrentSignalMask.Val &= ~(*set & IgnoredSignalsMask); + Thread->SignalInfo.CurrentSignalMask.Val &= ~(*set & IgnoredSignalsMask); } else if (how == SIG_SETMASK) { - ThreadData.CurrentSignalMask.Val = *set & IgnoredSignalsMask; + Thread->SignalInfo.CurrentSignalMask.Val = *set & IgnoredSignalsMask; } else { return -EINVAL; } - uint64_t HostMask = ThreadData.CurrentSignalMask.Val; + uint64_t HostMask = Thread->SignalInfo.CurrentSignalMask.Val; // Now actually set the host mask // This will hide from the guest that we are not actually setting all of the masks it wants for (size_t i = 0; i < MAX_SIGNALS; ++i) { @@ -1960,17 +1939,17 @@ uint64_t SignalDelegator::GuestSigProcMask(int how, const uint64_t* set, uint64_ *oldset = OldSet; } - CheckForPendingSignals(GetTLSThread()->Thread); + CheckForPendingSignals(Thread); return 0; } -uint64_t SignalDelegator::GuestSigPending(uint64_t* set, size_t sigsetsize) { +uint64_t SignalDelegator::GuestSigPending(FEX::HLE::ThreadStateObject* Thread, uint64_t* set, size_t sigsetsize) { if (sigsetsize > sizeof(uint64_t)) { return -EINVAL; } - *set = ThreadData.PendingSignals; + *set = Thread->SignalInfo.PendingSignals; sigset_t HostSet {}; if (sigpending(&HostSet) == 0) { @@ -1987,7 +1966,7 @@ uint64_t SignalDelegator::GuestSigPending(uint64_t* set, size_t sigsetsize) { return 0; } -uint64_t SignalDelegator::GuestSigSuspend(uint64_t* set, size_t sigsetsize) { +uint64_t SignalDelegator::GuestSigSuspend(FEX::HLE::ThreadStateObject* Thread, uint64_t* set, size_t sigsetsize) { if (sigsetsize > sizeof(uint64_t)) { return -EINVAL; } @@ -1995,9 +1974,9 @@ uint64_t SignalDelegator::GuestSigSuspend(uint64_t* set, size_t sigsetsize) { uint64_t IgnoredSignalsMask = ~((1ULL << (SIGKILL - 1)) | (1ULL << (SIGSTOP - 1))); // Backup the mask - ThreadData.PreviousSuspendMask = ThreadData.CurrentSignalMask; + Thread->SignalInfo.PreviousSuspendMask = Thread->SignalInfo.CurrentSignalMask; // Set the new mask - ThreadData.CurrentSignalMask.Val = *set & IgnoredSignalsMask; + Thread->SignalInfo.CurrentSignalMask.Val = *set & IgnoredSignalsMask; sigset_t HostSet {}; sigemptyset(&HostSet); @@ -2021,9 +2000,9 @@ uint64_t SignalDelegator::GuestSigSuspend(uint64_t* set, size_t sigsetsize) { // XXX: Might be unsafe if the signal handler adjusted the thread's signal mask // But since we don't support the guest adjusting the mask through the context object // then this is safe-ish - ThreadData.CurrentSignalMask = ThreadData.PreviousSuspendMask; + Thread->SignalInfo.CurrentSignalMask = Thread->SignalInfo.PreviousSuspendMask; - CheckForPendingSignals(GetTLSThread()->Thread); + CheckForPendingSignals(Thread); return Result == -1 ? -errno : Result; } diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/SignalDelegator.h b/Source/Tools/LinuxEmulation/LinuxSyscalls/SignalDelegator.h index 297dfc1f29..180653259f 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/SignalDelegator.h +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/SignalDelegator.h @@ -54,7 +54,7 @@ class SignalDelegator final : public FEXCore::SignalDelegator, public FEXCore::A ~SignalDelegator() override; // Called from the signal trampoline function. - void HandleSignal(int Signal, void* Info, void* UContext); + void HandleSignal(FEX::HLE::ThreadStateObject* Thread, int Signal, void* Info, void* UContext); void RegisterTLSState(FEX::HLE::ThreadStateObject* Thread); void UninstallTLSState(FEX::HLE::ThreadStateObject* Thread); @@ -82,11 +82,11 @@ class SignalDelegator final : public FEXCore::SignalDelegator, public FEXCore::A */ uint64_t RegisterGuestSignalHandler(int Signal, const GuestSigAction* Action, struct GuestSigAction* OldAction); - uint64_t RegisterGuestSigAltStack(const stack_t* ss, stack_t* old_ss); + uint64_t RegisterGuestSigAltStack(FEX::HLE::ThreadStateObject* Thread, const stack_t* ss, stack_t* old_ss); - uint64_t GuestSigProcMask(int how, const uint64_t* set, uint64_t* oldset); - uint64_t GuestSigPending(uint64_t* set, size_t sigsetsize); - uint64_t GuestSigSuspend(uint64_t* set, size_t sigsetsize); + uint64_t GuestSigProcMask(FEX::HLE::ThreadStateObject* Thread, int how, const uint64_t* set, uint64_t* oldset); + uint64_t GuestSigPending(FEX::HLE::ThreadStateObject* Thread, uint64_t* set, size_t sigsetsize); + uint64_t GuestSigSuspend(FEX::HLE::ThreadStateObject* Thread, uint64_t* set, size_t sigsetsize); uint64_t GuestSigTimedWait(uint64_t* set, siginfo_t* info, const struct timespec* timeout, size_t sigsetsize); uint64_t GuestSignalFD(int fd, const uint64_t* set, size_t sigsetsize, int flags); /** @} */ @@ -134,10 +134,8 @@ class SignalDelegator final : public FEXCore::SignalDelegator, public FEXCore::A void SaveTelemetry(); private: - FEX::HLE::ThreadStateObject* GetTLSThread(); - // Called from the thunk handler to handle the signal - void HandleGuestSignal(FEXCore::Core::InternalThreadState* Thread, int Signal, void* Info, void* UContext); + void HandleGuestSignal(FEX::HLE::ThreadStateObject* ThreadObject, int Signal, void* Info, void* UContext); /** * @brief Registers a signal handler for the host to handle a signal diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/Signals.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/Signals.cpp index d971f7ee7b..b59d9bf066 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/Signals.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/Signals.cpp @@ -25,15 +25,18 @@ struct GuestSigAction; namespace FEX::HLE { void RegisterSignals(FEX::HLE::SyscallHandler* Handler) { REGISTER_SYSCALL_IMPL(rt_sigprocmask, [](FEXCore::Core::CpuStateFrame* Frame, int how, const uint64_t* set, uint64_t* oldset) -> uint64_t { - return FEX::HLE::_SyscallHandler->GetSignalDelegator()->GuestSigProcMask(how, set, oldset); + return FEX::HLE::_SyscallHandler->GetSignalDelegator()->GuestSigProcMask(FEX::HLE::ThreadManager::GetStateObjectFromCPUState(Frame), + how, set, oldset); }); REGISTER_SYSCALL_IMPL(rt_sigpending, [](FEXCore::Core::CpuStateFrame* Frame, uint64_t* set, size_t sigsetsize) -> uint64_t { - return FEX::HLE::_SyscallHandler->GetSignalDelegator()->GuestSigPending(set, sigsetsize); + return FEX::HLE::_SyscallHandler->GetSignalDelegator()->GuestSigPending(FEX::HLE::ThreadManager::GetStateObjectFromCPUState(Frame), set, + sigsetsize); }); REGISTER_SYSCALL_IMPL(rt_sigsuspend, [](FEXCore::Core::CpuStateFrame* Frame, uint64_t* unewset, size_t sigsetsize) -> uint64_t { - return FEX::HLE::_SyscallHandler->GetSignalDelegator()->GuestSigSuspend(unewset, sigsetsize); + return FEX::HLE::_SyscallHandler->GetSignalDelegator()->GuestSigSuspend(FEX::HLE::ThreadManager::GetStateObjectFromCPUState(Frame), + unewset, sigsetsize); }); REGISTER_SYSCALL_IMPL(userfaultfd, [](FEXCore::Core::CpuStateFrame* Frame, int flags) -> uint64_t { diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/ThreadManager.h b/Source/Tools/LinuxEmulation/LinuxSyscalls/ThreadManager.h index 6defced075..68e5e6912e 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/ThreadManager.h +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/ThreadManager.h @@ -8,6 +8,8 @@ desc: Frontend thread management #pragma once +#include "LinuxSyscalls/Types.h" + #include #include #include @@ -29,6 +31,24 @@ struct ThreadStateObject : public FEXCore::Allocator::FEXAllocOperators { int32_t* clear_child_tid {0}; uint64_t robust_list_head {0}; } ThreadInfo {}; + + struct { + SignalDelegator* Delegator {}; + + void* AltStackPtr {}; + stack_t GuestAltStack { + .ss_sp = nullptr, + .ss_flags = SS_DISABLE, // By default the guest alt stack is disabled + .ss_size = 0, + }; + // This is the thread's current signal mask + FEX::HLE::GuestSAMask CurrentSignalMask {}; + // The mask prior to a suspend + FEX::HLE::GuestSAMask PreviousSuspendMask {}; + + uint64_t PendingSignals {}; + + } SignalInfo {}; }; class ThreadManager final { @@ -44,6 +64,10 @@ class ThreadManager final { return static_cast(Frame->Thread->FrontendPtr); } + static inline FEX::HLE::ThreadStateObject* GetStateObjectFromFEXCoreThread(FEXCore::Core::InternalThreadState* Thread) { + return static_cast(Thread->FrontendPtr); + } + FEX::HLE::ThreadStateObject* CreateThread(uint64_t InitialRIP, uint64_t StackPointer, FEXCore::Core::CPUState* NewThreadState = nullptr, uint64_t ParentTID = 0); void TrackThread(FEX::HLE::ThreadStateObject* Thread) { diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/FS.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/FS.cpp index 78dbb1e77a..fd29cf589c 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/FS.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/FS.cpp @@ -40,7 +40,8 @@ void RegisterFS(FEX::HLE::SyscallHandler* Handler) { REGISTER_SYSCALL_IMPL_X32( sigprocmask, [](FEXCore::Core::CpuStateFrame* Frame, int how, const uint64_t* set, uint64_t* oldset, size_t sigsetsize) -> uint64_t { - return FEX::HLE::_SyscallHandler->GetSignalDelegator()->GuestSigProcMask(how, set, oldset); + return FEX::HLE::_SyscallHandler->GetSignalDelegator()->GuestSigProcMask(FEX::HLE::ThreadManager::GetStateObjectFromCPUState(Frame), + how, set, oldset); }); } } // namespace FEX::HLE::x32 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Signals.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Signals.cpp index 456b1f697c..9f4e5a71b4 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Signals.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Signals.cpp @@ -77,7 +77,7 @@ void RegisterSignals(FEX::HLE::SyscallHandler* Handler) { // Only gets the lower 32-bits of the signal mask REGISTER_SYSCALL_IMPL_X32(sgetmask, [](FEXCore::Core::CpuStateFrame* Frame) -> uint64_t { uint64_t Set {}; - FEX::HLE::_SyscallHandler->GetSignalDelegator()->GuestSigProcMask(0, nullptr, &Set); + FEX::HLE::_SyscallHandler->GetSignalDelegator()->GuestSigProcMask(FEX::HLE::ThreadManager::GetStateObjectFromCPUState(Frame), 0, nullptr, &Set); return Set & ~0U; }); @@ -86,7 +86,8 @@ void RegisterSignals(FEX::HLE::SyscallHandler* Handler) { REGISTER_SYSCALL_IMPL_X32(ssetmask, [](FEXCore::Core::CpuStateFrame* Frame, uint32_t New) -> uint64_t { uint64_t Set {}; uint64_t NewSet = (~0ULL << 32) | New; - FEX::HLE::_SyscallHandler->GetSignalDelegator()->GuestSigProcMask(SIG_SETMASK, &NewSet, &Set); + FEX::HLE::_SyscallHandler->GetSignalDelegator()->GuestSigProcMask(FEX::HLE::ThreadManager::GetStateObjectFromCPUState(Frame), + SIG_SETMASK, &NewSet, &Set); return Set & ~0U; }); @@ -94,12 +95,13 @@ void RegisterSignals(FEX::HLE::SyscallHandler* Handler) { // The upper 32-bits are still active (unmasked) and can signal the program REGISTER_SYSCALL_IMPL_X32(sigsuspend, [](FEXCore::Core::CpuStateFrame* Frame, uint32_t Mask) -> uint64_t { uint64_t Mask64 = Mask; - return FEX::HLE::_SyscallHandler->GetSignalDelegator()->GuestSigSuspend(&Mask64, 8); + return FEX::HLE::_SyscallHandler->GetSignalDelegator()->GuestSigSuspend(FEX::HLE::ThreadManager::GetStateObjectFromCPUState(Frame), &Mask64, 8); }); REGISTER_SYSCALL_IMPL_X32(sigpending, [](FEXCore::Core::CpuStateFrame* Frame, compat_old_sigset_t* set) -> uint64_t { uint64_t HostSet {}; - uint64_t Result = FEX::HLE::_SyscallHandler->GetSignalDelegator()->GuestSigPending(&HostSet, 8); + uint64_t Result = + FEX::HLE::_SyscallHandler->GetSignalDelegator()->GuestSigPending(FEX::HLE::ThreadManager::GetStateObjectFromCPUState(Frame), &HostSet, 8); if (Result == 0) { // This old interface only returns the lower signals *set = HostSet & ~0U; diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Thread.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Thread.cpp index dc770e6174..68f487c29b 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Thread.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Thread.cpp @@ -219,7 +219,8 @@ void RegisterThread(FEX::HLE::SyscallHandler* Handler) { old64 = *old_ss; old64_ptr = &old64; } - uint64_t Result = FEX::HLE::_SyscallHandler->GetSignalDelegator()->RegisterGuestSigAltStack(ss64_ptr, old64_ptr); + uint64_t Result = FEX::HLE::_SyscallHandler->GetSignalDelegator()->RegisterGuestSigAltStack( + FEX::HLE::ThreadManager::GetStateObjectFromCPUState(Frame), ss64_ptr, old64_ptr); if (Result == 0 && old_ss) { *old_ss = old64; diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Thread.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Thread.cpp index f2d666cef9..d75647b465 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Thread.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Thread.cpp @@ -59,7 +59,8 @@ void RegisterThread(FEX::HLE::SyscallHandler* Handler) { })); REGISTER_SYSCALL_IMPL_X64(sigaltstack, [](FEXCore::Core::CpuStateFrame* Frame, const stack_t* ss, stack_t* old_ss) -> uint64_t { - return FEX::HLE::_SyscallHandler->GetSignalDelegator()->RegisterGuestSigAltStack(ss, old_ss); + return FEX::HLE::_SyscallHandler->GetSignalDelegator()->RegisterGuestSigAltStack( + FEX::HLE::ThreadManager::GetStateObjectFromCPUState(Frame), ss, old_ss); }); // launch a new process under fex