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>
4.1 KiB
address, classification, confidence, last_audit, aliases
| address | classification | confidence | last_audit | aliases | |
|---|---|---|---|---|---|
| 0x821B6DF4 | msvc_eh_catch_handler | high | 060 |
|
sub_821B6DF4 — MSVC C++ catch-handler thunk
Synopsis
A C++ catch-handler thunk emitted by the MSVC PowerPC C++ runtime. Dispatched by the EH machinery (_CxxFrameHandler3 equivalent) when a matching exception type is thrown — NOT a normal bl callee. AUDIT-058 mistakenly treated it as the top of a "static caller ladder" for sub_825070F0's activation; AUDIT-060 falsified that by reading the prolog and the .rdata reference context.
This is the canonical "MSVC EH FuncInfo metadata mistaken for call edges" case. Always check the prolog before assuming a 0-caller fn is a missing activator.
Evidence
- Disasm at
0x821B6DF4opens with the canonical MSVC catch-handler prolog:subi r31, r12, 112; mflr r12; stwu r1, -96(r1); .... The use ofr12(parent-frame pointer offset) andmflr r12is signature MSVC EH-handler shape. - Address
0x821B6DF4appears as a u32 value in only two places in the binary:.rdata:0x820C1994— embedded inside an MSVC FuncInfo struct. Bracketing bytes:FFFFFFFF 821B6DF4 19930522 00000001 820C1990 ....0x19930522is the MSVC FuncInfo magic..pdata:0x8211C678— exception-unwind metadata.
- AUDIT-060 Probe C-Win Windows Debug canary:
--log_lr_on_pc=0x821B6DF4, runs at 120s and 240s wallclock → 0 fires both runs. The matching exception is not thrown at this boot horizon. - AUDIT-060 Probe O ours:
--ctor-probe=0x821B6DF4 -n 500M→ 0 fires. - Body: single
bl 0x82183B78(an EH support routine) then return.
Activation
C++ exception runtime dispatch. Fires iff a try-block protected by the FuncInfo at 0x820C1990 catches a thrown object whose type matches the catch's CatchTypeInfo. Neither engine throws this exception at the probed horizon.
Static graph
- Static callers: 0 — and this is correct (0 callers does not imply dead; it implies "not a bl target").
- Callees:
sub_82183B78(EH support routine). - xrefs in DB will show
kind=indirector absent entries; the.rdatareference at0x820C1994is the FuncInfo binding, not a call edge.
Audit log
- AUDIT-060 (2026-05-12) — disassembled body; identified MSVC catch-handler prolog; cross-referenced
.rdatabytes to find FuncInfo magic0x19930522; probed in both engines at 240s/-n500M → 0 fires both sides. AUDIT-058's "caller ladder" framing falsified. New reading-error class #16 logged. [confirmed] - AUDIT-058 (2026-05-10) — claimed as "top of static caller ladder" for
sub_825070F0activation, walked:sub_825070F0 ← sub_824F7800 ← sub_824F7CD0 ← sub_824F8398 ← sub_821B55D8 ← sub_821B6DF4. All 6 fire 0× in ours; framed as missing activation. [STATUS: falsified by AUDIT-060 — the entire 6-fn chain is C++ EH unwind metadata; none of them are normal call edges; they fire only on specific exception throws.]
Open questions
- What exception type-id activates this catch? Parse the FuncInfo struct at
0x820C1990:- TryBlockMap entries → CatchTypeArray pointer → CatchType records (each has type_info* + handler ptr).
- The type_info string would identify the C++ class being caught.
- Is the matching throw site reachable in either engine at any boot horizon? If yes, when?
- Are the other 5 fns in the AUDIT-058 ladder ALL catch-handler thunks? Spot-check
sub_821B55D8,sub_824F8398,sub_824F7CD0,sub_824F7800,sub_825070F0. (sub_825070F0DOES fire 1× per AUDIT-058 — so at least it's not pure-EH; could be the actual throw site or a normal-call leaf.)
Cross-references
- FuncInfo location:
.rdata:0x820C1990(start of struct),0x820C1994contains this fn's pointer. .pdataunwind:0x8211C678.- Body callee:
sub_82183B78(EH support). - Companion ladder fns (need separate dossiers):
sub_821B55D8,sub_824F8398,sub_824F7CD0,sub_824F7800, sub_825070F0. - Audits: 058, 060.
- Artifacts:
audit-runs/audit-060-fnptr-array-bootstrap/canary-sub821B6DF4-120s.log,canary-sub821B6DF4-240s.log,ours-summary.md.