diff --git a/orbis-kernel/src/KernelContext.cpp b/orbis-kernel/src/KernelContext.cpp index da33bc43f..7ffc11f66 100644 --- a/orbis-kernel/src/KernelContext.cpp +++ b/orbis-kernel/src/KernelContext.cpp @@ -325,14 +325,14 @@ void Thread::sendSignal(int signo) { } } - if (pthread_sigqueue(getNativeHandle(), SIGUSR1, {.sival_int = signo})) { - perror("pthread_sigqueue"); - } - - // TODO: suspend uses another delivery confirmation if (signo != -1) { interruptedMtx.store(1, std::memory_order::release); + + if (pthread_sigqueue(getNativeHandle(), SIGUSR1, {.sival_int = signo})) { + perror("pthread_sigqueue"); + } + while (interruptedMtx.wait(1, std::chrono::microseconds(1000)) != std::errc{}) { if (interruptedMtx.load() == 0) { @@ -343,6 +343,10 @@ void Thread::sendSignal(int signo) { perror("pthread_sigqueue"); } } + } else { + if (pthread_sigqueue(getNativeHandle(), SIGUSR1, {.sival_int = signo})) { + perror("pthread_sigqueue"); + } } } diff --git a/rpcsx/main.cpp b/rpcsx/main.cpp index 7ee9075c2..9575e1b9e 100644 --- a/rpcsx/main.cpp +++ b/rpcsx/main.cpp @@ -8,6 +8,7 @@ #include "ipmi.hpp" #include "linker.hpp" #include "ops.hpp" +#include "orbis/ucontext.hpp" #include "orbis/utils/Logs.hpp" #include "rx/Config.hpp" #include "rx/mem.hpp" @@ -16,6 +17,7 @@ #include "vfs.hpp" #include "vm.hpp" #include "xbyak/xbyak.h" +#include #include #include #include @@ -170,6 +172,37 @@ handle_signal(int sig, siginfo_t *info, void *ucontext) { } else { rx::printStackTrace(reinterpret_cast(ucontext), 2); } + + if (orbis::g_currentThread != nullptr) { + auto toGuestSigno = [](int sig) -> std::optional { + switch (sig) { + case SIGSEGV: + return orbis::kSigSegv; + + case SIGBUS: + return orbis::kSigBus; + + case SIGFPE: + return orbis::kSigFpe; + + default: + return std::nullopt; + } + }; + + if (auto guestSigno = toGuestSigno(sig)) { + auto context = reinterpret_cast(ucontext); + bool inGuestCode = + context->uc_mcontext.gregs[REG_RIP] < orbis::kMaxAddress; + + if (inGuestCode) { + if (rx::thread::invokeSignalHandler(orbis::g_currentThread, + *guestSigno, context)) { + return; + } + } + } + } } struct sigaction act{}; diff --git a/rpcsx/thread.cpp b/rpcsx/thread.cpp index 9e354e9eb..ce222c819 100644 --- a/rpcsx/thread.cpp +++ b/rpcsx/thread.cpp @@ -129,42 +129,16 @@ handleSigUser(int sig, siginfo_t *info, void *ucontext) { } else if (guestSignal >= 0) { ORBIS_LOG_WARNING(__FUNCTION__, "handled signal", guestSignal, inGuestCode, ::getpid(), thread->tid); - auto it = thread->tproc->sigActions.find(guestSignal); - if (it != thread->tproc->sigActions.end()) { - auto guestContext = reinterpret_cast( - inGuestCode ? context : thread->context); + if (!rx::thread::invokeSignalHandler(thread, guestSignal, + inGuestCode ? context : nullptr)) { + // no handler, mark signal as delivered + std::uint32_t prevValue = 1; + if (thread->interruptedMtx.compare_exchange_strong(prevValue, 0)) { + thread->interruptedMtx.notify_one(); + } - auto sigact = it->second; - thread->setSigMask(sigact.mask); - auto handlerPtr = reinterpret_cast(sigact.handler); - - auto rsp = guestContext->uc_mcontext.gregs[REG_RSP]; - - ORBIS_LOG_WARNING(__FUNCTION__, "invoking signal handler", guestSignal, - rsp, thread->stackStart, thread->stackEnd); - - // FIXME: alt stack? - rsp -= 128; // redzone - rsp -= sizeof(orbis::SigFrame); - - // FIXME handle flags - auto &sigFrame = *std::bit_cast(rsp); - sigFrame = {}; - - rx::thread::copyContext(thread, sigFrame.context, *guestContext); - sigFrame.info.signo = guestSignal; - sigFrame.handler = handlerPtr; - - guestContext->uc_mcontext.gregs[REG_RDI] = guestSignal; // arg1, signo - guestContext->uc_mcontext.gregs[REG_RSI] = - std::bit_cast(&sigFrame.info); // arg2, siginfo - guestContext->uc_mcontext.gregs[REG_RDX] = - std::bit_cast(&sigFrame.context); // arg3, ucontext - guestContext->uc_mcontext.gregs[REG_RCX] = 0; // arg4, si_addr - guestContext->uc_mcontext.gregs[REG_RIP] = handlerPtr; - - guestContext->uc_mcontext.gregs[REG_RSP] = rx::alignDown(rsp, 16); + guestSignal = -1; } } @@ -186,6 +160,50 @@ std::size_t rx::thread::getSigAltStackSize() { return sigStackSize; } +bool rx::thread::invokeSignalHandler(orbis::Thread *thread, int guestSignal, + ucontext_t *context) { + auto it = thread->tproc->sigActions.find(guestSignal); + + if (it == thread->tproc->sigActions.end()) { + return false; + } + + auto guestContext = + reinterpret_cast(context ? context : thread->context); + + auto sigact = it->second; + thread->setSigMask(sigact.mask); + auto handlerPtr = reinterpret_cast(sigact.handler); + + auto rsp = guestContext->uc_mcontext.gregs[REG_RSP]; + + ORBIS_LOG_WARNING(__FUNCTION__, "invoking signal handler", guestSignal, rsp, + thread->stackStart, thread->stackEnd); + + // FIXME: alt stack? + rsp -= 128; // redzone + rsp -= sizeof(orbis::SigFrame); + + // FIXME handle flags + auto &sigFrame = *std::bit_cast(rsp); + sigFrame = {}; + + rx::thread::copyContext(thread, sigFrame.context, *guestContext); + sigFrame.info.signo = guestSignal; + sigFrame.handler = handlerPtr; + + guestContext->uc_mcontext.gregs[REG_RDI] = guestSignal; // arg1, signo + guestContext->uc_mcontext.gregs[REG_RSI] = + std::bit_cast(&sigFrame.info); // arg2, siginfo + guestContext->uc_mcontext.gregs[REG_RDX] = + std::bit_cast(&sigFrame.context); // arg3, ucontext + guestContext->uc_mcontext.gregs[REG_RCX] = 0; // arg4, si_addr + guestContext->uc_mcontext.gregs[REG_RIP] = handlerPtr; + + guestContext->uc_mcontext.gregs[REG_RSP] = rx::alignDown(rsp, 16); + return true; +} + void rx::thread::copyContext(orbis::MContext &dst, const mcontext_t &src) { // dst.onstack = src.gregs[REG_ONSTACK]; dst.rdi = src.gregs[REG_RDI]; diff --git a/rpcsx/thread.hpp b/rpcsx/thread.hpp index 75fb1ac5b..f3dcbc4f6 100644 --- a/rpcsx/thread.hpp +++ b/rpcsx/thread.hpp @@ -13,6 +13,8 @@ void setupThisThread(); void copyContext(orbis::MContext &dst, const mcontext_t &src); void copyContext(orbis::Thread *thread, orbis::UContext &dst, const ucontext_t &src); +bool invokeSignalHandler(orbis::Thread *thread, int signo, + ucontext_t *context = nullptr); void setContext(orbis::Thread *thread, const orbis::UContext &src); void invoke(orbis::Thread *thread); } // namespace rx::thread