D808 - a signal reaches a thread asleep on a lock

Status: decided Date: 2026-10-12

A signal raised on a thread asleep in scePthreadMutexLock (or POSIX pthread_mutex_lock, which answers through it) runs on that thread, as on a thread asleep in the other owned waits (D652). The lock's state is released while the handler runs, and the thread then waits for the lock again. The lock call marks the thread parked for the length of its wait, and a raise nudges lock waiters with the others.

Grounded in FreeBSD's libthr, which the platform's threads follow: a contended mutex sleeps in _umtx_op. A signal interrupts that sleep, its handler runs, and the lock is retried. D652's measurements found cross-thread delivery into a thread asleep in an address or umtx wait, which is the same sleep.

Why: PPSA03416's IL2CPP runtime stops the world by raising a signal on each thread (sceKernelRaiseException, through its PS5Util module). Each handler acknowledges on "SuspendSemaphore" and waits on "resumeEvent". The GC finaliser was asleep on a lock the collecting thread holds. Its raise was refused, so it never acknowledged, the collector waited forever, and the title's loading screen never ended (D806, D807 named the waits). With delivery, the collection completes and the title loads past it, to a shader using the cube-map instructions.

Rejected: