3 Commits

Author SHA1 Message Date
chrg6
222a025c52 Give back what a host thread keeps for itself when it ends.
Every guest thread is a host thread, and the game makes and ends them all through play. A thread that slept through plat_wait_ns kept a waitable timer, one that read or wrote a file an event for each, and one that decoded zstd through the host a decoder context of about 100 KiB; nothing closed or freed them when the thread ended, and a detached thread's own record stayed allocated. They are now given back when the thread's function returns: the handles in win32.c thread_main, the decoder context through plat_thread_end_hook, and the record by whichever of the thread and its detach comes last.

tests/thread_end_check.py runs 416 such threads and compares the process's handle count before and after. tests/sync_wake_check.c gets the two stand-ins kernel.c has needed since the service wait log, so that check builds and passes again. The Linux file only gains the hook call and was not compiled here.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
2026-11-12 15:18:25 -05:00
chrg6
92178ed511 Give the unit checks that build one runtime file a stub for the size lines' helper, so they link again.
The perf trace's size lines made kernel.c, fs_host.c and vk_gpa.c call perf_size, which the checks do not build. save_share_check also gets the stub it lacked for the write-back probe's switch.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
2026-11-10 23:34:31 -05:00
chrg6
094573bd26 Wake only the threads that wait for the event that was signalled.
A signalled kernel event, or a thread that ended, woke every thread blocked in WaitSynchronization. Each woken thread
takes a virtual core before it looks at its handles, asking a running thread of lower priority for its core when all
are held, finds nothing signalled and blocks again. The audio renderer signals its event 200 times a second, so every
thread that waits for a message, a timer or another thread's end did this 200 times a second at the cost of the
threads that were working.

A wait now records its handle list, and a signal wakes the waits that hold a handle of the signalled event or thread.
NX2NAVI_SYNC_WAKE_ALL=1 (or ab) wakes them all as before, and the sched line counts the waits woken and left asleep.

tests/sync_wake_check.py builds kernel.c with the rest of the runtime stubbed and checks the wakes, the timeouts, the
cancel and that none of 4,000 signals to eight looping waiters is lost, in both modes.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
2026-11-10 07:15:30 -05:00