From 2070056d164310dcd792541ae3d39b6e53319755 Mon Sep 17 00:00:00 2001 From: Ryan Houdek <Sonicadvance1@gmail.com> Date: Sat, 25 Nov 2023 07:53:43 -0800 Subject: [PATCH] FEXCore: Moves more SignalDelegator functions to the frontend As we are moving more and more OS specific code to the frontend, this is another set of functions that can be moved to FEXLoader from FEXCore. No functional change here, only code moved from protected to private and to FEXLoader's SignalDelegator. Once more thread handling is moved to the frontend we can move even more out of FEXCore. As follows: - CheckXIDHandler can get moved. - First pthread FEX makes would just call this. - Register/UnregisterTLSState - This can happen in the clone/thread handler once the frontend handles it. This leaves very little in the backend and is mostly an interface for passing signal data to the frontend that it needs once a signal has occured. It additionally also is used for `SignalThread`. --- FEXCore/Source/CMakeLists.txt | 1 - .../Source/Interface/Core/SignalDelegator.cpp | 41 ----------------- .../include/FEXCore/Core/SignalDelegator.h | 44 ------------------- Source/Tools/CommonTools/DummyHandlers.h | 14 +----- .../FEXLoader/LinuxSyscalls/GdbServer.cpp | 6 +-- .../Tools/FEXLoader/LinuxSyscalls/GdbServer.h | 6 ++- .../LinuxSyscalls/SignalDelegator.cpp | 36 ++++++++++++++- .../FEXLoader/LinuxSyscalls/SignalDelegator.h | 42 ++++++++++++++---- 8 files changed, 77 insertions(+), 113 deletions(-) delete mode 100644 FEXCore/Source/Interface/Core/SignalDelegator.cpp diff --git a/FEXCore/Source/CMakeLists.txt b/FEXCore/Source/CMakeLists.txt index 26f307e5d..0276f3d84 100644 --- a/FEXCore/Source/CMakeLists.txt +++ b/FEXCore/Source/CMakeLists.txt @@ -100,7 +100,6 @@ set (SRCS Interface/Core/OpcodeDispatcher/X87.cpp Interface/Core/OpcodeDispatcher/X87F64.cpp Interface/Core/OpcodeDispatcher.cpp - Interface/Core/SignalDelegator.cpp Interface/Core/X86Tables.cpp Interface/Core/X86DebugInfo.cpp Interface/Core/X86HelperGen.cpp diff --git a/FEXCore/Source/Interface/Core/SignalDelegator.cpp b/FEXCore/Source/Interface/Core/SignalDelegator.cpp deleted file mode 100644 index 32102b6eb..000000000 --- a/FEXCore/Source/Interface/Core/SignalDelegator.cpp +++ /dev/null @@ -1,41 +0,0 @@ -// SPDX-License-Identifier: MIT -#include <FEXCore/Core/SignalDelegator.h> -#include <FEXCore/Utils/LogManager.h> -#include <FEXHeaderUtils/Syscalls.h> - -#include <unistd.h> -#include <signal.h> - -namespace FEXCore { - void SignalDelegator::RegisterHostSignalHandler(int Signal, HostSignalDelegatorFunction Func, bool Required) { - SetHostSignalHandler(Signal, Func, Required); - FrontendRegisterHostSignalHandler(Signal, Func, Required); - } - - void SignalDelegator::HandleSignal(int Signal, void *Info, void *UContext) { - // Let the host take first stab at handling the signal - auto Thread = GetTLSThread(); - HostSignalHandler &Handler = HostHandlers[Signal]; - - if (!Thread) { - LogMan::Msg::AFmt("[{}] Thread has received a signal and hasn't registered itself with the delegate! Programming error!", FHU::Syscalls::gettid()); - } - else { - for (auto &Handler : Handler.Handlers) { - if (Handler(Thread, Signal, Info, UContext)) { - // If the host handler handled the fault then we can continue now - return; - } - } - - if (Handler.FrontendHandler && - Handler.FrontendHandler(Thread, Signal, Info, UContext)) { - return; - } - - // Now let the frontend handle the signal - // It's clearly a guest signal and this ends up being an OS specific issue - HandleGuestSignal(Thread, Signal, Info, UContext); - } - } -} diff --git a/FEXCore/include/FEXCore/Core/SignalDelegator.h b/FEXCore/include/FEXCore/Core/SignalDelegator.h index 70951a947..85cb0cccd 100644 --- a/FEXCore/include/FEXCore/Core/SignalDelegator.h +++ b/FEXCore/include/FEXCore/Core/SignalDelegator.h @@ -35,8 +35,6 @@ namespace Core { #endif }; } - using HostSignalDelegatorFunction = std::function<bool(FEXCore::Core::InternalThreadState *Thread, int Signal, void *info, void *ucontext)>; - class SignalDelegator { public: virtual ~SignalDelegator() = default; @@ -49,16 +47,6 @@ namespace Core { virtual void RegisterTLSState(FEXCore::Core::InternalThreadState *Thread) = 0; virtual void UninstallTLSState(FEXCore::Core::InternalThreadState *Thread) = 0; - /** - * @brief Registers a signal handler for the host to handle a signal - * - * It's a process level signal handler so one must be careful - */ - void RegisterHostSignalHandler(int Signal, HostSignalDelegatorFunction Func, bool Required); - - // Called from the thunk handler to handle the signal - void HandleSignal(int Signal, void *Info, void *UContext); - /** * @brief Check to ensure the XID handler is still set to the FEX handler * @@ -67,12 +55,6 @@ namespace Core { */ virtual void CheckXIDHandler() = 0; - constexpr static size_t MAX_SIGNALS {64}; - - // Use the last signal just so we are less likely to ever conflict with something that the guest application is using - // 64 is used internally by Valgrind - constexpr static size_t SIGNAL_FOR_PAUSE {63}; - struct SignalDelegatorConfig { bool StaticRegisterAllocation{}; bool SupportsAVX{}; @@ -124,31 +106,5 @@ namespace Core { protected: SignalDelegatorConfig Config; - - virtual FEXCore::Core::InternalThreadState *GetTLSThread() = 0; - virtual void HandleGuestSignal(FEXCore::Core::InternalThreadState *Thread, int Signal, void *info, void *ucontext) = 0; - - /** - * @brief Registers a signal handler for the host to handle a signal - * - * It's a process level signal handler so one must be careful - */ - virtual void FrontendRegisterHostSignalHandler(int Signal, HostSignalDelegatorFunction Func, bool Required) = 0; - virtual void FrontendRegisterFrontendHostSignalHandler(int Signal, HostSignalDelegatorFunction Func, bool Required) = 0; - - private: - struct HostSignalHandler { - fextl::vector<FEXCore::HostSignalDelegatorFunction> Handlers{}; - FEXCore::HostSignalDelegatorFunction FrontendHandler{}; - }; - std::array<HostSignalHandler, MAX_SIGNALS + 1> HostHandlers{}; - - protected: - void SetHostSignalHandler(int Signal, HostSignalDelegatorFunction Func, bool Required) { - HostHandlers[Signal].Handlers.push_back(std::move(Func)); - } - void SetFrontendHostSignalHandler(int Signal, HostSignalDelegatorFunction Func, bool Required) { - HostHandlers[Signal].FrontendHandler = std::move(Func); - } }; } diff --git a/Source/Tools/CommonTools/DummyHandlers.h b/Source/Tools/CommonTools/DummyHandlers.h index 3d673e3f4..a7c4bd6c6 100644 --- a/Source/Tools/CommonTools/DummyHandlers.h +++ b/Source/Tools/CommonTools/DummyHandlers.h @@ -34,21 +34,11 @@ class DummySignalDelegator final : public FEXCore::SignalDelegator, public FEXCo } protected: - // Called from the thunk handler to handle the signal - void HandleGuestSignal(FEXCore::Core::InternalThreadState *Thread, int Signal, void *Info, void *UContext) override {} - void RegisterTLSState(FEXCore::Core::InternalThreadState *Thread) override; void UninstallTLSState(FEXCore::Core::InternalThreadState *Thread) override; - FEXCore::Core::InternalThreadState *GetTLSThread() override; - - /** - * @brief Registers a signal handler for the host to handle a signal - * - * It's a process level signal handler so one must be careful - */ - void FrontendRegisterHostSignalHandler(int Signal, FEXCore::HostSignalDelegatorFunction Func, bool Required) override {} - void FrontendRegisterFrontendHostSignalHandler(int Signal, FEXCore::HostSignalDelegatorFunction Func, bool Required) override {} + private: + FEXCore::Core::InternalThreadState *GetTLSThread(); }; fextl::unique_ptr<FEXCore::HLE::SyscallHandler> CreateSyscallHandler(); diff --git a/Source/Tools/FEXLoader/LinuxSyscalls/GdbServer.cpp b/Source/Tools/FEXLoader/LinuxSyscalls/GdbServer.cpp index 867312df3..faac3143f 100644 --- a/Source/Tools/FEXLoader/LinuxSyscalls/GdbServer.cpp +++ b/Source/Tools/FEXLoader/LinuxSyscalls/GdbServer.cpp @@ -79,7 +79,7 @@ GdbServer::~GdbServer() { close(ListenSocket); } -GdbServer::GdbServer(FEXCore::Context::Context *ctx, FEXCore::SignalDelegator *SignalDelegation, FEXCore::HLE::SyscallHandler *const SyscallHandler) +GdbServer::GdbServer(FEXCore::Context::Context *ctx, FEX::HLE::SignalDelegator *SignalDelegation, FEXCore::HLE::SyscallHandler *const SyscallHandler) : CTX(ctx) , SyscallHandler {SyscallHandler} { // Pass all signals by default @@ -97,7 +97,7 @@ GdbServer::GdbServer(FEXCore::Context::Context *ctx, FEXCore::SignalDelegator *S // This is a total hack as there is currently no way to resume once hitting a segfault // But it's semi-useful for debugging. - for (uint32_t Signal = 0; Signal <= FEXCore::SignalDelegator::MAX_SIGNALS; ++Signal) { + for (uint32_t Signal = 0; Signal <= FEX::HLE::SignalDelegator::MAX_SIGNALS; ++Signal) { SignalDelegation->RegisterHostSignalHandler(Signal, [this] (FEXCore::Core::InternalThreadState *Thread, int Signal, void *info, void *ucontext) { if (PassSignals[Signal]) { // Pass signal to the guest @@ -989,7 +989,7 @@ GdbServer::HandledPacketType GdbServer::handleQuery(const fextl::string &packet) // We now have a semi-colon deliminated list of signals to pass to the guest process for (fextl::string tmp; std::getline(ss, tmp, ';'); ) { uint32_t Signal = std::stoi(tmp.c_str(), nullptr, 16); - if (Signal < FEXCore::SignalDelegator::MAX_SIGNALS) { + if (Signal < FEX::HLE::SignalDelegator::MAX_SIGNALS) { PassSignals[Signal] = true; } } diff --git a/Source/Tools/FEXLoader/LinuxSyscalls/GdbServer.h b/Source/Tools/FEXLoader/LinuxSyscalls/GdbServer.h index ecac744d6..b21308e32 100644 --- a/Source/Tools/FEXLoader/LinuxSyscalls/GdbServer.h +++ b/Source/Tools/FEXLoader/LinuxSyscalls/GdbServer.h @@ -19,11 +19,13 @@ $end_info$ #include <mutex> #include <stdint.h> +#include "LinuxSyscalls/SignalDelegator.h" + namespace FEX { class GdbServer { public: - GdbServer(FEXCore::Context::Context *ctx, FEXCore::SignalDelegator *SignalDelegation, FEXCore::HLE::SyscallHandler *const SyscallHandler); + GdbServer(FEXCore::Context::Context *ctx, FEX::HLE::SignalDelegator *SignalDelegation, FEXCore::HLE::SyscallHandler *const SyscallHandler); ~GdbServer(); // Public for threading @@ -96,7 +98,7 @@ private: fextl::string LibraryMapString{}; // Used to keep track of which signals to pass to the guest - std::array<bool, FEXCore::SignalDelegator::MAX_SIGNALS + 1> PassSignals{}; + std::array<bool, FEX::HLE::SignalDelegator::MAX_SIGNALS + 1> PassSignals{}; uint32_t CurrentDebuggingThread{}; int ListenSocket{}; fextl::string GdbUnixSocketPath{}; diff --git a/Source/Tools/FEXLoader/LinuxSyscalls/SignalDelegator.cpp b/Source/Tools/FEXLoader/LinuxSyscalls/SignalDelegator.cpp index 9186363f4..db49bc7dc 100644 --- a/Source/Tools/FEXLoader/LinuxSyscalls/SignalDelegator.cpp +++ b/Source/Tools/FEXLoader/LinuxSyscalls/SignalDelegator.cpp @@ -150,6 +150,38 @@ namespace FEX::HLE { return SigInfoLayout::LAYOUT_KILL; } + void SignalDelegator::HandleSignal(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()); + } + else { + SignalHandler &Handler = HostHandlers[Signal]; + for (auto &HandlerFunc : Handler.Handlers) { + if (HandlerFunc(Thread, Signal, Info, UContext)) { + // If the host handler handled the fault then we can continue now + return; + } + } + + if (Handler.FrontendHandler && + Handler.FrontendHandler(Thread, Signal, Info, UContext)) { + return; + } + + // Now let the frontend handle the signal + // It's clearly a guest signal and this ends up being an OS specific issue + HandleGuestSignal(Thread, Signal, Info, UContext); + } + } + + void SignalDelegator::RegisterHostSignalHandler(int Signal, HostSignalDelegatorFunction Func, bool Required) { + SetHostSignalHandler(Signal, Func, Required); + FrontendRegisterHostSignalHandler(Signal, Func, Required); + } + void SignalDelegator::SpillSRA(FEXCore::Core::InternalThreadState *Thread, void *ucontext, uint32_t IgnoreMask) { #ifdef _M_ARM_64 for (size_t i = 0; i < Config.SRAGPRCount; i++) { @@ -1811,7 +1843,7 @@ namespace FEX::HLE { ThreadData.Thread = nullptr; } - void SignalDelegator::FrontendRegisterHostSignalHandler(int Signal, FEXCore::HostSignalDelegatorFunction Func, bool Required) { + void SignalDelegator::FrontendRegisterHostSignalHandler(int Signal, HostSignalDelegatorFunction Func, bool Required) { // Linux signal handlers are per-process rather than per thread // Multiple threads could be calling in to this std::lock_guard lk(HostDelegatorMutex); @@ -1819,7 +1851,7 @@ namespace FEX::HLE { InstallHostThunk(Signal); } - void SignalDelegator::FrontendRegisterFrontendHostSignalHandler(int Signal, FEXCore::HostSignalDelegatorFunction Func, bool Required) { + void SignalDelegator::FrontendRegisterFrontendHostSignalHandler(int Signal, HostSignalDelegatorFunction Func, bool Required) { // Linux signal handlers are per-process rather than per thread // Multiple threads could be calling in to this std::lock_guard lk(HostDelegatorMutex); diff --git a/Source/Tools/FEXLoader/LinuxSyscalls/SignalDelegator.h b/Source/Tools/FEXLoader/LinuxSyscalls/SignalDelegator.h index 3a5e7b0a3..3c81ae3d6 100644 --- a/Source/Tools/FEXLoader/LinuxSyscalls/SignalDelegator.h +++ b/Source/Tools/FEXLoader/LinuxSyscalls/SignalDelegator.h @@ -40,20 +40,36 @@ namespace FEX::HLE { class SignalDelegator final : public FEXCore::SignalDelegator, public FEXCore::Allocator::FEXAllocOperators { public: + constexpr static size_t MAX_SIGNALS {64}; + + // Use the last signal just so we are less likely to ever conflict with something that the guest application is using + // 64 is used internally by Valgrind + constexpr static size_t SIGNAL_FOR_PAUSE {63}; + // Returns true if the host handled the signal // Arguments are the same as sigaction handler SignalDelegator(FEXCore::Context::Context *_CTX, const std::string_view ApplicationName); ~SignalDelegator() override; + // Called from the signal trampoline function. + void HandleSignal(int Signal, void *Info, void *UContext); + void RegisterTLSState(FEXCore::Core::InternalThreadState *Thread) override; void UninstallTLSState(FEXCore::Core::InternalThreadState *Thread) override; + /** + * @brief Registers a signal handler for the host to handle a signal + * + * It's a process level signal handler so one must be careful + */ + void RegisterHostSignalHandler(int Signal, HostSignalDelegatorFunction Func, bool Required); + /** * @brief Registers a signal handler for the host to handle a signal specifically for guest handling * * It's a process level signal handler so one must be careful */ - void RegisterHostSignalHandlerForGuest(int Signal, FEX::HLE::HostSignalDelegatorFunctionForGuest Func); + void RegisterHostSignalHandlerForGuest(int Signal, HostSignalDelegatorFunctionForGuest Func); void RegisterFrontendHostSignalHandler(int Signal, HostSignalDelegatorFunction Func, bool Required); /** @@ -107,21 +123,27 @@ namespace FEX::HLE { FEX_CONFIG_OPT(ParanoidTSO, PARANOIDTSO); void SaveTelemetry(); - protected: - // Called from the thunk handler to handle the signal - void HandleGuestSignal(FEXCore::Core::InternalThreadState *Thread, int Signal, void *Info, void *UContext) override; + private: + FEXCore::Core::InternalThreadState *GetTLSThread(); - FEXCore::Core::InternalThreadState *GetTLSThread() override; + // Called from the thunk handler to handle the signal + void HandleGuestSignal(FEXCore::Core::InternalThreadState *Thread, int Signal, void *Info, void *UContext); /** * @brief Registers a signal handler for the host to handle a signal * * It's a process level signal handler so one must be careful */ - void FrontendRegisterHostSignalHandler(int Signal, FEXCore::HostSignalDelegatorFunction Func, bool Required) override; - void FrontendRegisterFrontendHostSignalHandler(int Signal, FEXCore::HostSignalDelegatorFunction Func, bool Required) override; + void FrontendRegisterHostSignalHandler(int Signal, HostSignalDelegatorFunction Func, bool Required); + void FrontendRegisterFrontendHostSignalHandler(int Signal, HostSignalDelegatorFunction Func, bool Required); + + void SetHostSignalHandler(int Signal, HostSignalDelegatorFunction Func, bool Required) { + HostHandlers[Signal].Handlers.push_back(std::move(Func)); + } + void SetFrontendHostSignalHandler(int Signal, HostSignalDelegatorFunction Func, bool Required) { + HostHandlers[Signal].FrontendHandler = std::move(Func); + } - private: FEX_CONFIG_OPT(Is64BitMode, IS64BIT_MODE); FEX_CONFIG_OPT(Core, CORE); fextl::string const ApplicationName; @@ -155,6 +177,10 @@ namespace FEX::HLE { FEX::HLE::HostSignalDelegatorFunctionForGuest GuestHandler{}; GuestSigAction GuestAction{}; DefaultBehaviour DefaultBehaviour {DEFAULT_TERM}; + + // Callbacks + fextl::vector<HostSignalDelegatorFunction> Handlers{}; + HostSignalDelegatorFunction FrontendHandler{}; }; std::array<SignalHandler, MAX_SIGNALS + 1> HostHandlers{};