kernel-threads (2026-10-27)¶
Timer preemption (SMO stall)¶
runtime/src/threads.c: a slice thread looks at every virtual core every 2 ms. A thread that waits for a core which its owner should give up (better priority, or equal priority after a 10 ms slice, NAPPLE_SLICE_MS) makes the owner switch: owners inside an svc get the existing svc-exit checkpoint, owners running guest code get SIGPROF; the handler (on the thread's signal stack) switches only when the interrupted pc is original guest text (never inside the runtime, so no host lock is held) and the TLR disable_count is 0 (otherwise interrupt_flag is raised and SynchronizePreemptionState switches, as on the kernel).
Evidence: before, SMO on a fresh save stalled at about 7 700 frames in 3 of 3 runs (thread 0x6b prio 47 spinning on core 0, main thread prio 44 waiting); after, 280 s headless gave 16 737 frames; tools/golden smo route (260 s, validation on) 14 211 frames, frames 8000 and 9000 captured (Mario in the carpet scene); one existing gfx warning (storage buffer not in a pool), not kernel.
Unit test runtime/tests/host/test_threads_preempt.c (P1 better-priority waiter vs spinner, P2 equal-priority sharing, P3 disable_count, P4 worse priority does not preempt): hangs without the feature (NAPPLE_SLICE_MS=0), 7 checks pass with it. Limits: code in the patch area (rewritten sequences) and AArch32 JIT code is never interrupted by the signal (only svc boundaries switch there); proposal for the rewriter owner: a counter-based yield at loop back-edges if a spin shows up there.
LAS SetTerminateResult 0x35f202 (about 1 start in 14)¶
Root cause (found with the svc ring and NAPPLE_FS_TRACE): 0x35f202 is the guest nn::fs::Unmount aborting because its mount name was no longer registered: the game's save thread (0x53) mounts "save", probes savedata/screenshot files, commits, unmounts, in steps, while the main thread runs the same probes when its own timer fires. A Commit of an unchanged root did a clonefile + sync() (about 50 ms, once per probe), so the save thread fell far behind the main thread and the two ran their mount/unmount sequences interleaved (on a console the save thread is done long before). fs.c now skips the snapshot when nothing was written since the last one (journal_commit: not dirty and a snapshot exists = no-op, still counted). test_fs_journal marks the root dirty where its raw writes bypass the IPC handlers (as IFile::Write does) and checks the no-op.
Evidence: 5 failures in about 75 starts before (e2e-like environment: fresh save, NAPPLE_AMIIBO, input script, 4 s); 0 in 150 starts after. The e2e KNOWN entry and its retry for 0x35f202 are removed.
ACNH¶
- Break at sdk+0xc80730 and the reboot SIGBUS at sdk+0x383f78: not reproduced in 20 + 25 + 25 boot/reboot pairs (base 3.0.0 and the 3.0.3 update, fonts present, e2e-like environment, with and without 10 busy loops) and 8 more loaded starts. Analysis: sdk+0xc80730 is the SDK's generic abort (any fatal result), sdk+0x383f78 is a table lookup on a pixel buffer pointer; SIGBUS on macOS is a protection fault on the PROT_NONE guest reservation (a page not committed). Not fixed; the e2e KNOWN entry for the Break stays.
- New under load (also reported by gfx-depth-views, about 1 start in 10 there, 2 of 37 here with 10 busy loops):
CRASH signal=11 fault=0x8 pc=main+0x6d65a4about 1 s in (3.0.3), a worker thread (prio 48) reading*(*(main+0x532f378)+8)= null, a singleton whose field is set by another game thread later. A start-up ordering race between game threads that the host scheduler under load exposes; not reproducible without load, root writer not identified (the NAPPLE_WATCH on the singleton only saw zeroing writes). Added to the e2e KNOWN list so the boot step retries it. Tools added for the next attempt:NAPPLE_SVC_RING=1(dumps on Break and crash: the last svcs per thread with IPC command and result, then all thread states),NAPPLE_THREAD_LOG=1,NAPPLE_FS_TRACE=1(now with OpenFile / GetEntryType / Commit and thread ids). - e2e mii-db flake with ACNH first: the step is wall-clock scripted; it now retries up to 3 times with a new nickname (3 of 3 cold direct runs passed here without the retry, so the flake was not reproduced).
Verified¶
make -C runtime test test-services test-host; SMO 280 s and golden route; LAS 4 s x 150; ACNH 130 boot/reboot starts; MK8D, LAS, SMO 45 s boots exit 0 with no CRASH. All runs with NAPPLE_AUDIO_OFF=1.