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>
This commit is contained in:
MechaCat02
2026-06-05 07:19:08 +02:00
parent acd1656753
commit ef93a4fa14
620 changed files with 108303 additions and 1 deletions

View File

@@ -0,0 +1,102 @@
# 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.rs``KernelObject::schema_object_type()`.
+14 LOC.
- `crates/xenia-kernel/src/state.rs``alloc_handle_for` emit hook. +24 LOC.
- `crates/xenia-kernel/src/exports.rs``nt_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.rs``xam_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.cc``TryGetCurrentThread` accessor
+ `XThread::Exit` thread.exit emit. +12 LOC.
- `src/xenia/kernel/util/object_table.cc``AddHandle`/`RemoveHandle` hooks
+ `SchemaObjectType` mapping. +35 LOC.
- `src/xenia/kernel/xboxkrnl/xboxkrnl_threading.cc``ExCreateThread`
thread.create emit, `xeKeWaitForSingleObject` + `NtWaitForSingleObjectEx`
wait.begin emits. +30 LOC.
### Diff tool
- `tools/diff-events/diff_events.py``SKIP_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).