Repository navigation
feat(libkernel): deliver sceKernelRaiseException on Linux - #1431
Conversation
|
Please split this into separate PRs: the per-thread |
|
Since Windows wasn't run, I ran it there before the split, in case it helps the Windows half: Windows 10 (19045), MinGW-w64 GCC 15.2.0 (WinLibs), Release,
In the toggling hang, main waits in MinGW's A way out could be to identify the current thread on the delivery path without emutls: compare |
|
Follow-up: the same deadlock reproduces on |
24f89cf to
7714301
Compare
|
The branch now has only the Linux |
|
Also gets Hollow Knight: Silksong (PPSA12544) further on Linux (Arch, GCC, RX 9070 XT). On current With this branch merged on top as well, that raise is delivered. The title loads |
adriadam10
left a comment
There was a problem hiding this comment.
Thanks for splitting this. Two things before it can be reviewed and merged:
- The branch conflicts with
mainincore/libs/tests/GuestRaiseException.cpp(#1478 changed it). Please rebase and rerunguest_raise_exceptionandguest_signals. - The title and description still describe the five-commit version (per-thread
sigprocmask, AudioOutsleepUs, 409 ctest results, stress runs, mutation checks for code that is no longer here), as @oneandonlydean asked on Oct 9. Please rewrite them for the current diff: LinuxsceKernelRaiseExceptiondelivery, the startup signal block inscePthreadCreate, and the MXCSR clamp. Update "Tested" with what you ran on this head, and the list of overlapping PRs.
Useful for the description: the Silksong (PPSA12544) log @hugodearaujo posted, where main stops at sceKernelRaiseException not implemented.
|
Another title this gets further on Linux: God of War Sons of Sparta (PPSA28997, Unity IL2CPP). Its GC stops threads with To test it I had to rebase it onto
I can share the resolved diff if it helps. |
sceKernelRaiseException threw on Linux, so a title whose garbage collector stops threads with it (Unity's PS5Util raises SIGUSR1 on each thread and reads mc_rsp from the handler's context) could not run there. The raise now sends the host SIGUSR1 to the target thread with pthread_kill. The host handler, installed on first use with SA_SIGINFO and SA_RESTART, builds the FreeBSD-layout ucontext from the interrupted registers and the FXSAVE area, calls the guest handler on the target's own stack and writes the registers back, so the handler's changes reach the interrupted code, as they do on Windows. errno is left as the handler leaves it, as libthr does. A raise on another thread takes the target's join lock with the host signal blocked and returns ESRCH once the thread has finished, so a detached thread's pthread_t is never signalled after it exits. The pthread_t is recorded when the thread is created or adopted. Handlers are now lock-free atomics, as the host handler reads them. guest_raise_exception now runs on every platform. It also checks that r13 and xmm8 reach the handler and that r12 and xmm8 written by the handler reach the interrupted code. AI-assisted: yes Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LwJx7AHrSUaMGSpEGhL1Kb
…ndler's MXCSR Two defects found in review of the Linux delivery: A raise right after scePthreadCreate reached the new thread before RunThread set currentThread, so scePthreadSelf() in the handler adopted a second handle, and could deadlock on glibc's thread lock when the signal interrupted pthread_getattr_np. The creator now blocks all signals around the std::thread construction, so the child starts with them blocked, and RunThread restores the creator's mask once the thread is registered, as libthr does. A raise in that window stays pending and is delivered just before the entry runs. A handler that set reserved MXCSR bits made rt_sigreturn fail with SIGSEGV. The MXCSR the handler leaves is now masked with the frame's MXCSR_MASK (0xffbf when it reads 0), as FreeBSD's fpusetregs does, on both platforms; Windows also keeps CONTEXT.MxCsr equal to FltSave.MxCsr. guest_raise_exception raises right after each of 50 thread creations and checks scePthreadSelf() in the handler, and its context round trip sets a reserved MXCSR bit and FZ and checks that only FZ is kept. AI-assisted: yes Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LwJx7AHrSUaMGSpEGhL1Kb
7714301 to
c356112
Compare
adriadam10
left a comment
There was a problem hiding this comment.
Rebased onto current main (c356112) and fixed the two points from the earlier review ourselves:
- Conflicts resolved: guest threads now start with
pthread_create, so the startup signal block wraps that call andRunThreadrestores the creator's mask;GuestRaiseException.cppnow runs on every platform, with the Windows-only parts under#ifdef _WIN32; removed the duplicatedhandlerSelf. - Title and description rewritten for the current diff (Linux delivery, startup signal block, MXCSR clamp), with the Silksong and God of War: Sons of Sparta reports.
Checked: guest_raise_exception 20/20 in a row, guest_signals, guest_exception_handler and guest_pthread_* green on Linux; the test fails without the source changes. Windows not run here.
What
sceKernelRaiseExceptionthrewNotImplementedon Linux, so a title whose garbage collector stops threads with it (Unity's PS5Util module: installs a SIGUSR1 handler withsceKernelInstallExceptionHandler, raises it on each thread and readsmc_rspfrom the context) could not run there. Two commits:feat(libkernel): deliver sceKernelRaiseException on Linux: the raise sends the host SIGUSR1 to the target thread withpthread_kill(model: shadPS4exception.cpp, asigactionwrapper withSA_SIGINFO | SA_RESTART). The host handler builds the FreeBSD-layoutucontextthe Windows path already uses (general registers, rip, rsp, rflags, cs, ss, 512-byte FXSAVE area), calls the guest handler on the target's own stack and writes the registers back. Only the 416 bytes up to XMM15 are written back: the rest of the FXSAVE area holds the kernel's XSAVE frame marker. A raise on another thread blocks the host signal, takes the target's join lock and returnsESRCHonce the thread has finished. The handler table is lock-free because the host handler reads it.fix(libkernel): keep raises off unregistered threads and clamp the handler's MXCSR:scePthreadCreateblocks all signals aroundpthread_createandRunThreadrestores the creator's mask once the thread is registered, so a raise right after creation cannot reach a thread whosescePthreadSelf()would adopt a second handle. The MXCSR a handler leaves is masked withMXCSR_MASK(0xffbf when it reads 0), as FreeBSD'sfpusetregsdoes, on both platforms; without it a reserved bit madert_sigreturnfail with SIGSEGV.guest_raise_exceptionis now registered on every platform. TechnicalDebt: the "throws on Linux" line is replaced by what still differs from the console (the handler runs wherever the thread was interrupted, host waits resume, calls Linux does not restart return early orEINTR).Tested
Rebased onto
mainac2c5c0 (the reviewer resolved the conflicts with thepthread_createthread start and the Windows-only test). Linux, GCC, libkernel scope:guest_raise_exceptionpasses 20/20 in a row,guest_signals,guest_exception_handlerand theguest_pthread_*tests pass; the new test fails without the source changes. Covers: self, busy, waiting insceKernelWaitSema, blocked on a host mutex, leaving a wait; register round trip (r12, r13, xmm8, MXCSR including a reserved bit); 50 raises right afterscePthreadCreatecheckingscePthreadSelf()in the handler; a finished thread returnsESRCH.Third parties: Hollow Knight: Silksong (PPSA12544, Arch, RX 9070 XT, @hugodearaujo) gets past
sceKernelRaiseException not implemented; God of War Sons of Sparta (PPSA28997, Arch, RTX 3050, @GustavoGamarra95) boots and plays several levels with this branch and #1482. Windows: not run here; @popcoder565 ran the pre-split branch on Windows 10.Checklist
main; no other open PR implements the same functionsNotImplemented_nid_no_patch); silent stubs are listed in TechnicalDebt.mdfiles or images added to the repository (attach them to this PR)Cloud credits project contribution