diff --git a/core/libs/prx/libkernel/System/src/Signals.cpp b/core/libs/prx/libkernel/System/src/Signals.cpp index f1ee8327e..93dfb9fad 100644 --- a/core/libs/prx/libkernel/System/src/Signals.cpp +++ b/core/libs/prx/libkernel/System/src/Signals.cpp @@ -162,6 +162,11 @@ int APS5_VABI sigprocmask_nid_postfix(int how, const void* set, void* previousSe return _sigprocmask_nid_postfix(how, static_cast(set), static_cast(previousSet)); } + +int APS5_VABI pthread_sigmask_nid_postfix(int how, const GuestSignalSet* set, GuestSignalSet* previousSet) { + if (set != nullptr && (how < 1 || how > 3)) return 22; + return _sigprocmask_nid_postfix(how, set, previousSet); +} } extern "C" { diff --git a/core/libs/tests/GuestSignals.cpp b/core/libs/tests/GuestSignals.cpp index dc5bf1a96..b90cb37c9 100644 --- a/core/libs/tests/GuestSignals.cpp +++ b/core/libs/tests/GuestSignals.cpp @@ -10,6 +10,7 @@ Handler APS5_VABI signal_nid_postfix(int, Handler); int APS5_VABI raise_nid_postfix(int); int APS5_VABI sigaction_nid_postfix(int, const void*, void*); int APS5_VABI sigprocmask_nid_postfix(int, const void*, void*); +int APS5_VABI pthread_sigmask_nid_postfix(int, const void*, void*); int* APS5_VABI __error_nid_postfix(); int APS5_VABI _is_signal_return_nid_postfix(std::uint64_t); } @@ -59,6 +60,16 @@ int main() { Require(sigprocmask_nid_postfix(2, &blocked, nullptr) == 0); Require(sigprocmask_nid_postfix(1, nullptr, &previous) == 0); Require(previous.bits[0] == 0); + *__error_nid_postfix() = 0; + Require(pthread_sigmask_nid_postfix(1, &blocked, nullptr) == 0); + Require(pthread_sigmask_nid_postfix(0, &blocked, &previous) == 22); + Require(pthread_sigmask_nid_postfix(4, &blocked, &previous) == 22); + Require(*__error_nid_postfix() == 0); + Require(pthread_sigmask_nid_postfix(0, nullptr, &previous) == 0); + Require(previous.bits[0] == 0x20); + Require(sigprocmask_nid_postfix(1, nullptr, &previous) == 0 && previous.bits[0] == 0x20); + Require(pthread_sigmask_nid_postfix(2, &blocked, &previous) == 0 && previous.bits[0] == 0x20); + Require(pthread_sigmask_nid_postfix(1, nullptr, &previous) == 0 && previous.bits[0] == 0); const auto callback = reinterpret_cast(Callback); const auto infoCallback = reinterpret_cast(InfoCallback); diff --git a/docs/dev/TechnicalDebt.md b/docs/dev/TechnicalDebt.md index 4656d0fbb..515a9f2f5 100644 --- a/docs/dev/TechnicalDebt.md +++ b/docs/dev/TechnicalDebt.md @@ -319,6 +319,7 @@ Throughout the project, every function at every stage either **does exactly what - [sceKernelRaiseException](../../core/libs/prx/libkernel/System/src/Exception.cpp) delivers on Windows only and throws on Linux - [sceKernelRaiseException](../../core/libs/prx/libkernel/System/src/Exception.cpp) builds the handler's `ucontext` with FreeBSD's amd64 layout (16-byte sigmask, `mcontext` at 0x40, `mc_rsp` at 0xf8); the console's layout is not verified beyond the fields PS5Util reads - [sceKernelRaiseException](../../core/libs/prx/libkernel/System/src/Exception.cpp) does not consult the target thread's signal mask +- [pthread_sigmask](../../core/libs/prx/libkernel/System/src/Signals.cpp) (libkernel) shares the process-wide mask of `sigprocmask` and `_sigprocmask`, which keeps only the first 32 signals; FreeBSD keeps a mask per thread - [sceKernelRaiseException](../../core/libs/prx/libkernel/System/src/Exception.cpp) reaches a thread that waits in an alertable `TimedWait` wait through an APC. A thread blocked anywhere else, including all waits under `APS5_COARSE_TIMED_WAITS` and host waits inside the emulator, is redirected and runs the handler only when that wait returns - [sceKernelRaiseException](../../core/libs/prx/libkernel/System/src/Exception.cpp) on Windows runs the handler wherever the target thread was interrupted. It waits only while the thread is inside winpthreads or restoring a context through `NtContinue`, and throws if that lasts 1 s, so a handler that calls into other host code the thread was interrupted in, such as the C runtime's heap or a lock of the emulator, can deadlock on it or reenter it - [sigaltstack](../../core/libs/prx/libkernel/System/src/Signals.cpp) (libkernel) records each thread's alternate signal stack and reports it back, following FreeBSD's `kern_sigaltstack` (`EINVAL` for flags other than `SS_DISABLE`, `ENOMEM` below `MINSIGSTKSZ` 2048), but handlers never run on it, so `SS_ONSTACK` and `EPERM` are never reported