The blocked mask of sigprocmask, _sigprocmask, pthread_sigmask and
sigsuspend was one process-wide set, so a thread changing its mask changed
every thread's, and scePthreadCreate did not hand the creating thread's mask
to the new thread. Each guest thread now has its own blocked mask and handler
holds, and a new thread starts with its creator's mask. The pending set stays
the process-wide one, so a signal that raise leaves pending is still taken by
sigwait and sigtimedwait on any thread and delivered by the first thread that
unblocks it. A SIGALRM expiry checks the mask of the thread that armed the
timer.
Fixes#2879.
Claude-Session: https://claude.ai/code/session_012SLQbhAiexxW6TtjYToW8a
On macOS under Rosetta, Aps5StartGuest moves the main thread off the host
stack and releases the old range to the guest arena. dyld keeps its own
pointers into the process start block at the top of that range and offers
no call that redirects them, where argv and environ have one:
_NSGetExecutablePath copies the path string out of the block on every
call, so the first call after the move read unmapped memory and the
process died with KERN_PROTECTION_FAILURE. A title does not have to call
it: libxpc reaches it from xpc_connection_resume, and ShaderCacheDirectory
calls it for the shader disk cache.
Release the old stack only up to the pages that hold the block, and only
while argv still points into the stack. They are the top two pages, 8 KiB
of the 8372224-byte stack here, so a title that fixes a mapping over that
range now fails with a host region overlap; the rest is free as before.
guest_main_stack_move asked for a 64 KiB guest mapping aligned down from
a local of main, which falls inside the kept pages. It now probes the
64 KiB below them, requires the kept pages to be refused, and calls
_NSGetExecutablePath after the move, which segfaults without this change.
cpuset_getaffinity and cpuset_setaffinity return ERANGE from 24 bytes, as a PS5 payload process did (rooklz sweep, #7135 comment 6391606624: 8 to 16 accepted, below 8 and from 24 up ERANGE), and throw for the unmeasured 17 to 23, as pthread_getaffinity_np does. The tests that used 32 bytes use 16 and pin 7, 24, 32 and 64 to ERANGE. The setter entry records that the console answers EPERM for a CPU outside the process's set where this clips and returns 0.
cpuset_getaffinity at CPU_LEVEL_ROOT returns 0xffff, as a PS5 payload process read it (rooklz, #7135 comment 6390891591), instead of throwing; the target is checked as at the other levels. The level 2 base-set test now passes 8 and 16 bytes, which the console accepts (it returns ERANGE from 24 bytes), instead of depending on the 32 bytes it rejects. The debt entry records the root measurement and that the title root set is unmeasured.
Carry #7135 by @AlexOfTheForest. Preserve current checked guest-memory copies and unrelated debt; remove the ten newly added unsupported-call throw assertions while retaining implemented success and error coverage.
Co-authored-by: Alexej Szpevák <[email protected]>
The conflict with #13908 in docs/dev/debt/libkernel.md keeps both sides: this branch's pthread_getaffinity_np entry, followed by #13908's sentence on the EFAULT fallback for a mask pointer that cannot be read or written.
A title is jailed (agreed on #11216). FreeBSD 11.4 prison_priv_check denies
PRIV_SCHED_RTPRIO, PRIV_SCHED_SET and PRIV_SCHED_SETPRIORITY to a jailed caller.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
The run report now records how far a run got (loaded, started, first draw,
first present), the frames presented and the average frame rate, the selected
GPU, the number of shaders compiled, failed and served from the cache, the
instructions the shader recompiler could not translate, the guest image
formats looked up or rejected, and the descriptor kinds that shaders bind.
The counters are relaxed atomics and are only touched while a report is being
collected. The window system's request to quit is recorded as the reason a run
ended.
rooklz measured on a PS5 that pthread_getaffinity_np accepts any set of 8 to
16 bytes, zero-fills it past byte 8, and returns ERANGE below 8 bytes and from
24 up. Sets of 17 to 23 bytes are not measured and still throw.
scePthreadCondSignalto and pthread_cond_signalto_np answered EPERM for a
handle that is not a live thread, where a PS5 on firmware 13.60 returns
ESRCH. The check sits between the null-thread and not-waiting checks, as
that console orders them.
The mutex yield step counts each yield in a counter that
MutexYieldsForTest_nid_no_patch reads. With no spins and a yield count
of 5, a waiter woken while another thread holds its mutex must yield
exactly 5 times before it blocks, for each mutex type and for the outer
level of a recursive mutex held twice. With WakingLock::lock calling
the native lock directly the count stays 0 and the test aborts.
Co-Authored-By: Claude Opus 5.5 <[email protected]>