[AUDIT-059 R-D2] Phase D auto-signal POC confirms audit-049 wedge diagnosis

Hook NtCreateEvent for the silph::UImpl tid=13 chain (entry=0x821748F0,
start_context=0x4024a840, frame-1 LR=0x821CB15C inside sub_821CB030+0x128)
and auto-signal the resulting handle after XENIA_SILPH_UI_AUTOSIGNAL_DELAY
instructions. Env-gated; default off.

SR4 verdict B (partial unwedge):
- handle 0x1078 signal_attempts 0->1
- tid=13 Blocked(WaitAny[0x1078]) -> Ready pc=0x824a9108
- ExCreateThread 10 -> 12 (new silph::UImpl tid=14, worker tid=15)
- New downstream wedges 0x1084 + 0x1088
- cxx_throw runtime_error on tid=5 inside R26 dispatcher
  (BST not-registered instance lhs=0x715a7af0)
- VdSwap stays 1; no draws (POC is diagnostic, not final fix)

Confirms Phase C diagnosis end-to-end. The real signaler must (a) drive
NtSetEvent on the silph KEVENT AND (b) register the dispatcher's BST
instance upstream; this POC only does (a).

Reading-error class #20: ctx.lr at kernel export entry is the thunk
wrapper's return slot, NOT the guest caller's post-bl PC. Walk back-chain
1 step to get frames[1].lr.

Reading-error class #21: --parallel and lockstep have SEPARATE outer
loops in main.rs (run_execution_parallel line 2928 vs run_execution
line 2706). Per-round hooks must be wired in BOTH paths.

Files:
- crates/xenia-cpu/src/scheduler.rs: GuestThread.start_entry/start_context
  fields + spawn() population + current_thread_entry_and_ctx() helper
- crates/xenia-kernel/src/state.rs: AutoSignalPending struct, env-parsed
  silph_autosignal_delay, pending Vec, last_cycle_hint, set_now_cycle_hint,
  maybe_register_silph_autosignal (walks back-chain), fire_due_silph_autosignals
- crates/xenia-kernel/src/exports.rs: hook in nt_create_event
- crates/xenia-app/src/main.rs: fire-site + cycle hint in both outer loops
- audit-runs/audit-059-handle-disambiguation/round-D2-autosignal-poc/FINDINGS.md

Tests 655/655 green. Default behavior byte-identical when env unset.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
MechaCat02
2026-06-11 18:38:38 +02:00
parent 481591fdb2
commit db90ad0f7d
5 changed files with 334 additions and 0 deletions

View File

@@ -2780,6 +2780,13 @@ fn run_execution(
RoundCtl::BreakOuter => break,
RoundCtl::Continue => {}
}
// ITERATE-2C Phase D — deposit the current instruction count so
// `nt_create_event` can compute absolute auto-signal deadlines,
// then drain any pending auto-signals whose deadline has passed.
// Both calls are no-ops when `XENIA_SILPH_UI_AUTOSIGNAL_DELAY`
// is unset (the pending queue stays empty).
kernel.set_now_cycle_hint(stats.instruction_count);
kernel.fire_due_silph_autosignals(stats.instruction_count);
dispatch_graphics_interrupts(
kernel,
mem,
@@ -3204,6 +3211,15 @@ fn run_execution_parallel(
}
let mut guard = pre_outcome.1;
// ITERATE-2C Phase D — same auto-signal hook as the lockstep
// path. Held under the same `kernel_arc` guard the rest of
// this prologue runs under, so no extra locking.
{
let s = stats_mtx.lock().expect("stats mutex poisoned");
guard.set_now_cycle_hint(s.instruction_count);
guard.fire_due_silph_autosignals(s.instruction_count);
}
// Iterate-2.BE — host-driven synchronous ISR dispatch.
// Runs under the kernel lock while workers are still parked
// at the phaser B2 barrier (the coordinator hasn't published