16. The futex timeout, and what the two threading probes still owe
031-stackattr and 032-syncaddr were
authored on 2026-09-07 (D322) against the sibling emulator's two open
premises about threading. Both are validated on the host build and
neither has been on hardware. This is what they deliberately do not
reach.
The wait's third register
sceKernelSyncOnAddressWait is declared with two
arguments - an address and a value - which is what three retail titles
pass, every observed call leaving the third register zero. FreeBSD's
_umtx_op(2), the citable analogue, has a timeout slot
there.
It is not probed, and it cannot be probed the way the width was. The width question has two safe outcomes: a 64-bit comparison returns, a 32-bit one blocks on a worker the main thread releases anyway. A timeout has no such symmetry - the measurement is how long the call waits, so a wrong guess at the unit either returns instantly and establishes nothing or outlives the run. Declaring the parameter to find out would be declaring an arity nothing establishes, which principle 2 forbids.
What would settle it: a session that can bring a known unit to it - a
wait on a matching word with a bounded third argument on the worker
thread, timed against sceKernelGetProcessTimeCounter, with
the existing wake as the recovery path if it never returns. It is a
small addition to 032-syncaddr once the unit is a
hypothesis rather than a blank.
Until then the sibling refuses a non-zero third register rather than model it, which is the honest state on both sides.
What a hardware run turns into an answer
Neither section has run on a console. Every check reads
assumed or derived until one does, and these
are the records to read out of it:
| record | what it settles |
|---|---|
031-stackattr/address-is-the-base placement |
1 the address is the stack's lowest byte, 2 its top. The sibling assumes the first and a collector's scan bound depends on it |
031-stackattr/self-describes address and size |
the real span of the main thread's stack, against which its
sceKernelIsStack bounds can be read |
031-stackattr/fresh-attr-names-no-stack |
whether a set nothing configured reports a stack at all, or leaves the out-parameter untouched |
032-syncaddr/compare-width |
64 or 32. The sibling models 64 from an export layout, never measured |
032-syncaddr/wait-returns-on-mismatch code |
what a wait on an already-differing word answers - the path a caller takes on every wake that arrived first |
032-syncaddr/wake-releases-a-waiter code |
what a wake answers with one waiter blocked, and whether it is a status or a count |
032-syncaddr/wake-with-no-waiter code |
the same with nobody waiting. A count would come back zero here and one above, which tells the two apart |
The sized variants, still censused
libkernel_sync_on_address2 exports
sceKernelSyncOnAddressWait8, 16,
32 and 64, and they remain in the census for
presence only. Nothing calls them: no title anybody has traced imports
one, and the plain pair is what the Unity shim uses. If
compare-width comes back 32, the
64 spelling becomes the interesting one and this is where
to start.
What the sections needed that did not exist
scePthreadAttrInit and its family had no host
implementation, so 010-kernel/thread-attributes
had been skipping on every host build since it was written - a check
that had never passed a known-good implementation, which CLAUDE.md is
explicit is not evidence. Stubs were written for the attribute family
and the futex pair, and that check now runs and passes. Worth knowing
that the host build's skips are not all inert: some of them are checks
nobody has validated.