Files
xenia-rs/docs/functions/sub_824ACB38.md
MechaCat02 ad45873a1b ITERATE-2.V: scheduler priority aging closes 18-day AUDIT-049 wedge
Priority aging in xenia-cpu/scheduler.rs:pick_runnable
(effective_priority = base + age_bonus(now_round - last_run_round),
capped at +31, AGING_ROUNDS_PER_BONUS=1). Strict-priority was parking
priority=0 threads behind CPU-bound priority=15 audio mixer
(sub_824D1328 guest spinwait at PC=0x824d1404 on CPU5). Aging
eventually picks the starved thread, breaking the producer-consumer
cycle that caused 5-tid wedge at PC=0x824ac578 since AUDIT-049 (10 May).

Cascade observed: tid=13 clean exit; events 121K -> 13M (107x); last
host_ns 767ms -> 51,011ms (66x); 8 new threads spawn; VdSwap 1 -> 2.

Complete two-day iterate sequence (2026-05-27 -> 2026-05-28):
- 2.F: VdSwap drain timeout 900ms -> 1ms (xenia-gpu/handle.rs); 876x
       perf win on VdSwap kernel callback
- 2.H: vA0000000 physical heap bucket added (state.rs, exports.rs);
       ctx_ptrs now in 0xA0000000-0xBFFFFFFF range matching canary
- 2.L: Phase-A diff harness categorized [return_value mismatch],
       [status mismatch], [args_resolved.path mismatch] tags
       (tools/diff-events/diff_events.py); closes reading-error #41
       (silent test-harness state leak invalidating trace diffs)
- 2.M: always-on exit-thread-state.json sibling to Phase-A JSONL
       (event_log.rs + xenia-app/main.rs); closes reading-error #42
       (Phase-A blind to blocked-forever waits)
- 2.Q: signal.match kernel instrumentation in NtSetEvent /
       NtReleaseSemaphore / KeSetEvent / KeReleaseSemaphore
       (exports.rs); emits target_handle + waiter_count + waiter_tids
- 2.T: wake.requested kernel instrumentation in wake_eligible_waiters
       (exports.rs); emits target_tid + transition + new_state
- 2.V: scheduler priority aging (xenia-cpu/scheduler.rs) [keystone]

Plus accumulated WIP from earlier May (contention_manifest,
phase_b_snapshot, xam/xaudio enhancements, analysis db, xex loader,
xenia-app main loop, etc.). Audit-runs/ artifacts remain untracked
per project convention.

Tests: 300 xenia-cpu / 227 xenia-kernel / 5 xenia-app / 19 xenia-path
/ 30+ smaller suites -- all PASS, 0 regressions. Determinism preserved
(2x cold runs bit-identical at 13,003,881 events post-2.V).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-29 07:27:26 +02:00

57 lines
3.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
address: 0x824ACB38
classification: crt_init_driver
confidence: high
last_audit: 060
aliases:
- "CRT driver"
- "vtable-slot enumerator (NOT a static-ctor list iterator)"
---
# sub_824ACB38 — CRT init driver / vtable-slot enumerator
## Synopsis
CRT-style driver called from `entry_point` (or near it). Body is 224 bytes (`0x824ACB38..0x824ACC18`). Contains two enumeration loops over fnptr-array regions at `0x82870xxx`. AUDIT-050 framed it as "iterates 0x82870xxx fnptr arrays (557 slots, 82 non-NULL)" and concluded a half-bootstrapped state; AUDIT-060 found this framing semantically misleading — the slots are runtime vtable-registration entries, not C++ static initializers, and the "82 non-NULL" count obscures a structural 160-slot intentional zero gap.
## Evidence
- Body anatomy at `0x824ACB38..0x824ACC18` (AUDIT-060 disasm):
- `+0x00..+0x2C` — preamble + one optional dispatch through fn-ptr at `[0x82023F08]` (= `0x825F1630`, an LZ-runtime thunk).
- `+0x30..+0x6C`**loop A**: enumerate u32 slots in `[0x828708C8, 0x828708D4)` — 3 slots. Filter: non-NULL. `bctrl` at `0x824ACBA0`.
- `+0x80..+0xB8`**loop B**: enumerate u32 slots in `[0x82870010, 0x828708C4)` — 557 slots. Filter: non-NULL AND `!= 0xFFFFFFFF`. `bctrl` at `0x824ACBEC`.
- `+0xC4` — epilogue, `blr`.
- Array layout (AUDIT-060 dumped at -n 1M and -n 500M; both identical):
- `0x82870010..0x828702E8` — populated with `0x82xxxxxx` pointers (vtable methods).
- `0x828702F0..0x82870580`**PERMANENTLY ZERO** across both dumps (160 of 557 slots = 28.7%).
- `0x82870590..0x828708C4` — populated with `0x82xxxxxx` pointers.
- `0x828708C8..0x828708D4` — loop-A array, populated (small CRT helpers).
- Static-DB cross-check: the 557-slot region contains 14+ separate small `vtable`-classified arrays at `0x82870014/0x24/0x94/0xC8/0x16C/0x214/0x238/0x250/0x2A8/0x2C0/0x2E4/0x5A0/0x62C/0x870`, NOT a single CRT static-ctor list. NO statically-detected arrays in `[0x82870300, 0x828705A0)` — the gap is intentional padding between two vtable clusters.
## Activation
Called once from `entry_point`-near code (per AUDIT-050 — exact caller PC not in AUDIT-060 trace). The driver enumerates all slot entries; each non-NULL entry is `bctrl`'d once.
## Static graph
- Static callers: 1 (from boot entry path; exact PC to confirm).
- Callees: indirect (`bctrl`) — targets are the contents of the enumerated slots.
## Audit log
- **AUDIT-060 (2026-05-12)** — disassembled body, identified structure (2 loops, gap), confirmed slot contents are runtime vtable entries rather than C++ static-ctor function pointers. The "82 non-NULL" AUDIT-050 count was correct per-slot but missed the structural 160-slot intentional gap. Driver fires 1× at -n 500M as expected (single boot enumeration). [confirmed]
- **AUDIT-050 (2026-05-10)** — framed as "CRT driver iterates 0x82870xxx fnptr arrays (557 slots, 82 non-NULL)". Structurally correct but semantically misleading ("static-ctor list" implication was wrong). [STATUS: partially superseded by AUDIT-060 — the "iterate fnptr array" claim stands; the "static-ctor list" implication does not.]
## Open questions
- What invokes this driver in `entry_point`? Find exact caller PC.
- Are the 14+ small vtable clusters in `[0x82870010, 0x828708C4)` enumerated by THIS driver, or by separate driver functions? If multiple drivers exist for the same region, the gap might be region-partitioning, not padding.
- For ours: are all 397 non-NULL slots dispatched at runtime? If some slot dispatch falls through (e.g. predicate skips it), that would be a real bug — needs runtime confirmation via `--branch-probe=0x824ACBA0,0x824ACBEC` (loop bodies).
## Cross-references
- LZ-runtime thunk at `+0x00..+0x2C`: `0x825F1630`.
- Fnptr-array region: `0x82870010..0x828708D4`.
- Audits: 045 (DB schema caveat: `v_call_graph` uses `xrefs.source`; prefer `xrefs.source_func`), 050, 060.
- Artifacts: `audit-runs/audit-060-fnptr-array-bootstrap/ours-dump-500M.stdout`.