Skip to content

Commit

Permalink
SignalDelegator: Refactor how thread local data is stored
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Sonicadvance1 committed Aug 24, 2024
1 parent 2829ad5 commit 8214b8c
Show file tree
Hide file tree
Showing 8 changed files with 107 additions and 98 deletions.
139 changes: 59 additions & 80 deletions Source/Tools/LinuxEmulation/LinuxSyscalls/SignalDelegator.cpp

Large diffs are not rendered by default.

14 changes: 6 additions & 8 deletions Source/Tools/LinuxEmulation/LinuxSyscalls/SignalDelegator.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
/** @} */
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
24 changes: 24 additions & 0 deletions Source/Tools/LinuxEmulation/LinuxSyscalls/ThreadManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ desc: Frontend thread management

#pragma once

#include "LinuxSyscalls/Types.h"

#include <FEXCore/Core/Context.h>
#include <FEXCore/fextl/vector.h>
#include <FEXCore/Utils/SignalScopeGuards.h>
Expand All @@ -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 {
Expand All @@ -44,6 +64,10 @@ class ThreadManager final {
return static_cast<FEX::HLE::ThreadStateObject*>(Frame->Thread->FrontendPtr);
}

static inline FEX::HLE::ThreadStateObject* GetStateObjectFromFEXCoreThread(FEXCore::Core::InternalThreadState* Thread) {
return static_cast<FEX::HLE::ThreadStateObject*>(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) {
Expand Down
3 changes: 2 additions & 1 deletion Source/Tools/LinuxEmulation/LinuxSyscalls/x32/FS.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
10 changes: 6 additions & 4 deletions Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Signals.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
});

Expand All @@ -86,20 +86,22 @@ 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;
});

// Only masks the lower 32-bits of the signal mask
// 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;
Expand Down
3 changes: 2 additions & 1 deletion Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Thread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
3 changes: 2 additions & 1 deletion Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Thread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 8214b8c

Please sign in to comment.