Merge pull request #4501 from JunChi1022/mask_signal_at_defer

LinuxSyscalls: Update signal mask at deferring time
This commit is contained in:
Ryan Houdek authored and GitHub committed 2025-04-16 10:56:40 -07:00
commit 8ff7497d59
3 files changed
+36 -15

No files matched your search

@@ -536,6 +536,27 @@ static bool IsAsyncSignal(const siginfo_t* Info, int Signal) {
return true;
}
uint64_t SignalDelegator::GetNewSigMask(int Signal) const {
const SignalHandler& Handler = HostHandlers[Signal];
// Set up a new mask based on this signals signal mask
uint64_t NewMask = Handler.GuestAction.sa_mask.Val;
// If NODEFER then the new signal mask includes this signal
if (!(Handler.GuestAction.sa_flags & SA_NODEFER)) {
NewMask |= (1ULL << (Signal - 1));
}
// Walk our required signals and stop masking them if requested
for (size_t i = 0; i < MAX_SIGNALS; ++i) {
if (HostHandlers[i + 1].Required.load(std::memory_order_relaxed)) {
// Never mask our required signals
NewMask &= ~(1ULL << i);
}
}
return NewMask;
}
void SignalDelegator::HandleGuestSignal(FEX::HLE::ThreadStateObject* ThreadObject, int Signal, void* Info, void* UContext) {
auto Thread = ThreadObject->Thread;
ucontext_t* _context = (ucontext_t*)UContext;
@@ -561,6 +582,8 @@ void SignalDelegator::HandleGuestSignal(FEX::HLE::ThreadStateObject* ThreadObjec
const auto& Top = ThreadObject->SignalInfo.DeferredSignalFrames.back();
Signal = Top.Signal;
SigInfo = Top.Info;
// sig mask has been updated at the defer time, recover the original mask
memcpy(&_context->uc_sigmask, &Top.SigMask, sizeof(uint64_t));
ThreadObject->SignalInfo.DeferredSignalFrames.pop_back();
// Until we re-protect the page to PROT_NONE, FEX will now *permanently* defer signals and /not/ check them.
@@ -594,11 +617,19 @@ void SignalDelegator::HandleGuestSignal(FEX::HLE::ThreadStateObject* ThreadObjec
"Deferred signals vector hit "
"capacity size. This will "
"likely crash! Asserting now!");
ThreadObject->SignalInfo.DeferredSignalFrames.emplace_back(ThreadStateObject::DeferredSignalState {
.Info = SigInfo,
.Signal = Signal,
.SigMask = _context->uc_sigmask.__val[0],
});
uint64_t NewMask = GetNewSigMask(Signal);
// Update our host signal mask so we don't hit race conditions with signals
// This allows us to maintain the expected signal mask through the guest signal handling and then all the way back again
memcpy(&_context->uc_sigmask, &NewMask, sizeof(uint64_t));
// Now update the faulting page permissions so it will fault on write.
mprotect(reinterpret_cast<void*>(&Thread->InterruptFaultPage), sizeof(Thread->InterruptFaultPage), PROT_NONE);
@@ -633,21 +664,7 @@ void SignalDelegator::HandleGuestSignal(FEX::HLE::ThreadStateObject* ThreadObjec
} else {
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;
// If NODEFER then the new signal mask includes this signal
if (!(Handler.GuestAction.sa_flags & SA_NODEFER)) {
NewMask |= (1ULL << (Signal - 1));
}
// Walk our required signals and stop masking them if requested
for (size_t i = 0; i < MAX_SIGNALS; ++i) {
if (HostHandlers[i + 1].Required.load(std::memory_order_relaxed)) {
// Never mask our required signals
NewMask &= ~(1ULL << i);
}
}
uint64_t NewMask = GetNewSigMask(Signal);
// Update our host signal mask so we don't hit race conditions with signals
// This allows us to maintain the expected signal mask through the guest signal handling and then all the way back again
@@ -277,6 +277,8 @@ private:
bool HandleSignalPause(FEXCore::Core::InternalThreadState* Thread, int Signal, void* info, void* ucontext);
bool HandleSIGILL(FEXCore::Core::InternalThreadState* Thread, int Signal, void* info, void* ucontext);
uint64_t GetNewSigMask(int Signal) const;
std::mutex HostDelegatorMutex;
std::mutex GuestDelegatorMutex;
bool SupportsAVX;
@@ -18,6 +18,7 @@ $end_info$
#include <FEXCore/Utils/Profiler.h>
#include <FEXCore/Utils/SignalScopeGuards.h>
#include <bits/types/sigset_t.h>
#include <cstdint>
#include <linux/seccomp.h>
@@ -37,6 +38,7 @@ struct ThreadStateObject : public FEXCore::Allocator::FEXAllocOperators {
struct DeferredSignalState {
siginfo_t Info;
int Signal;
uint64_t SigMask;
};
FEXCore::Core::InternalThreadState* Thread;