Merge pull request #3290 from Sonicadvance1/move_signaldelegator

FEXCore: Moves more SignalDelegator functions to the frontend
This commit is contained in:
Ryan Houdek 2023-11-27 13:46:11 -08:00 committed by GitHub
commit 6e8af295c5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 77 additions and 113 deletions

View File

@ -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/X86HelperGen.cpp
Interface/Core/ArchHelpers/Arm64Emitter.cpp

View File

@ -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);
}
}
}

View File

@ -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);
}
};
}

View File

@ -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();

View File

@ -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;
}
}

View File

@ -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{};

View File

@ -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);

View File

@ -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{};