Files
xenia-rs/audit-runs/phase-c15a-schema-wiring/audit.md
MechaCat02 ef93a4fa14 handoff: VSync/event-wedge fixes + iterate 2.A–2.BC research notes
Source changes (dormant parity infra, retained from iterate 2.AI/2.AO):
- xenia-kernel/exports.rs: nt_create_event manual_reset polarity +
  related event wiring
- xenia-gpu/mmio_region.rs: D1MODE_VBLANK_VLINE_STATUS hardcode parity

Also lands the audit-runs/ analysis notes (.md/.txt/.json digests) for the
iterate 2.x VSync/0x10e8/0x1004 wedge investigation. Raw trace dumps
(.jsonl/.gz/.csv/.stdout) and agent worktrees (.claude/) are gitignored as
regenerable local artifacts — see memory + HANDOFF for the running findings.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05 07:19:08 +02:00

5.5 KiB
Raw Blame History

Phase C+15-α Schema-Wiring Audit (2026-05-14)

Phase 1 — Wired/unwired matrix (pre-session)

Kind Canary emits? Ours emits? Status (pre) Priority
schema_version yes yes wired
import.call yes yes wired
kernel.call yes yes wired (+C+10)
kernel.return yes yes wired
handle.create declared declared stubbed HIGH
handle.destroy declared declared stubbed HIGH
thread.create declared declared stubbed HIGH
thread.exit declared declared stubbed HIGH
wait.begin declared declared stubbed HIGH
wait.end declared declared stubbed HIGH
thread.suspend declared not in API unwired LOW
thread.resume declared not in API unwired LOW
vfs.open declared not in API redundant? MEDIUM
vfs.read declared not in API high-vol LOW
vfs.close declared not in API redundant? MEDIUM
mem.write declared not in API opt-in LOW

Phase 2/3 — Kinds wired this session

Wired symmetrically in both engines (cvar-gated default-off):

  • handle.create — emitted from KernelState::alloc_handle_for (ours) / ObjectTable::AddHandle (canary). 39+ call sites covered via centralized hook.
  • handle.destroy — emitted from nt_close + xam_task_close_handle (ours) / ObjectTable::RemoveHandle (canary).
  • thread.create — emitted from ex_create_thread (ours) / ExCreateThread in xboxkrnl_threading.cc (canary). After spawn succeeds.
  • thread.exit — emitted from ex_terminate_thread (ours) / XThread::Exit (canary). Canary's XThread::Exit covers both explicit ExTerminateThread and implicit thread-entry returns.
  • wait.begin — emitted from nt_wait_for_single_object_ex + ke_wait_for_single_object (ours) / xeKeWaitForSingleObject + NtWaitForSingleObjectEx (canary).

Deferred (v1.2):

  • wait.end — design challenge: wait can park the guest thread, and the wake-status path differs between engines. Sync outcome status is already captured in the immediately-following kernel.return. Async wake outcome surfaced in subsequent events.
  • thread.suspend / thread.resume — low-frequency; defer until needed.
  • vfs.* — redundant with kernel.call for Nt*File. Skip per schema-v1 audit recommendation.
  • mem.write — opt-in only (separate cvar); high-volume.

Code summary

Ours (~140 LOC)

  • crates/xenia-kernel/src/event_log.rs — registry + auto helpers (register_handle_semantic_id, lookup_handle_semantic_id, forget_handle_semantic_id, emit_handle_create_auto, emit_handle_destroy_auto). +85 LOC.
  • crates/xenia-kernel/src/objects.rsKernelObject::schema_object_type(). +14 LOC.
  • crates/xenia-kernel/src/state.rsalloc_handle_for emit hook. +24 LOC.
  • crates/xenia-kernel/src/exports.rsnt_close destroy emit, ex_create_thread thread.create emit, ex_terminate_thread thread.exit emit, nt_wait_for_single_object_ex + ke_wait_for_single_object wait.begin emits,
    • decode_timeout_ns helper. +85 LOC.
  • crates/xenia-kernel/src/xam.rsxam_task_close_handle destroy emit. +14 LOC.

Canary (~130 LOC)

  • src/xenia/kernel/event_log.h — registry API (RegisterHandleSemanticId, LookupHandleSemanticId, ForgetHandleSemanticId, EmitHandleCreateAuto, EmitHandleDestroyAuto). +20 LOC.
  • src/xenia/kernel/event_log.cc — per-tid counter map (was per-host-thread thread_local; produced duplicate tid_event_idx for tid=0 across host threads — a bug in the pre-session implementation), CurrentTid non-asserting via new XThread::TryGetCurrentThread, registry helpers, auto-emit wrappers. +60 LOC net.
  • src/xenia/kernel/xthread.h + xthread.ccTryGetCurrentThread accessor
    • XThread::Exit thread.exit emit. +12 LOC.
  • src/xenia/kernel/util/object_table.ccAddHandle/RemoveHandle hooks
    • SchemaObjectType mapping. +35 LOC.
  • src/xenia/kernel/xboxkrnl/xboxkrnl_threading.ccExCreateThread thread.create emit, xeKeWaitForSingleObject + NtWaitForSingleObjectEx wait.begin emits. +30 LOC.

Diff tool

  • tools/diff-events/diff_events.pySKIP_PAYLOAD_FIELDS_BY_KIND now skips handle_semantic_id (cross-engine creating_tid differs, so SIDs are engine-local), parent_tid, handles_semantic_ids, woken_by_semantic_id. +6 LOC.

Bug found and fixed this session

Pre-session bug: canary's t_tid_event_idx was a host-thread-local global, not a tid-keyed counter. When AddHandle runs from multiple host threads with tid==0 (boot init + early XThread bootstrap before guest tid is assigned), each host thread had its own counter starting at 0, producing duplicate tid_event_idx values within the tid=0 stream. The diff tool rejected the file with "events out of order at index 8". Fixed by replacing the thread_local with a tid-keyed std::unordered_map + mutex (matches ours's design).