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:
@@ -4848,6 +4848,44 @@ pub(crate) fn handle_consume(state: &mut KernelState, handle: u32) {
|
||||
}
|
||||
}
|
||||
|
||||
/// 2.AJ — reciprocal-shadow clear for guest-pointer auto-reset dispatchers.
|
||||
///
|
||||
/// `handle_consume` only updates the kernel-side shadow's `signaled` /
|
||||
/// `count`. For guest-pointer dispatchers (handle is a guest VA into a
|
||||
/// `KEVENT` / `KSEMAPHORE` struct in title memory), the **source of truth
|
||||
/// for the next wait's `refresh_pkevent_shadow_from_guest` is the guest
|
||||
/// memory `SignalState` at `[ptr + 4]`**. Without clearing that on
|
||||
/// consume, a wait that fast-paths re-signals the shadow from stale
|
||||
/// guest memory on its next iteration → spin-forever loops (e.g.
|
||||
/// Sylpheed tid=7 polling its VSync-signaled dispatcher 6.5 M times in
|
||||
/// 208 s post-2.AI). Canary doesn't need this because `XEvent::Set` /
|
||||
/// auto-reset host-event `Wait` consume on a single host OS object —
|
||||
/// there is no shadow/guest split to bridge.
|
||||
///
|
||||
/// Mirrors the rising-edge `signal_state != 0 → shadow.signaled = true`
|
||||
/// in `refresh_pkevent_shadow_from_guest`. We only mutate the falling
|
||||
/// edge — i.e. only clear guest memory when we just cleared our shadow.
|
||||
/// NT-handle objects (small int handles) are unaffected because they
|
||||
/// have no guest-memory dispatcher to bridge to.
|
||||
pub(crate) fn handle_consume_reciprocal_clear(
|
||||
state: &KernelState,
|
||||
mem: &GuestMemory,
|
||||
handle: u32,
|
||||
) {
|
||||
if handle < 0x1_0000 {
|
||||
return;
|
||||
}
|
||||
match state.objects.get(&handle) {
|
||||
Some(KernelObject::Event { manual_reset, signaled, .. })
|
||||
| Some(KernelObject::Timer { manual_reset, signaled, .. }) => {
|
||||
if !*manual_reset && !*signaled {
|
||||
mem.write_u32(handle + 4, 0);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
/// Register a guest thread as a waiter on a handle (for later wake).
|
||||
pub(crate) fn handle_enqueue_waiter(state: &mut KernelState, handle: u32, r: ThreadRef) {
|
||||
match state.objects.get_mut(&handle) {
|
||||
@@ -5560,6 +5598,9 @@ fn do_wait_single(ctx: &mut PpcContext, state: &mut KernelState, handle: u32, ti
|
||||
state.audit_wait(handle, ctx.lr as u32, "do_wait_single", 0);
|
||||
if handle_signaled(state, handle) {
|
||||
handle_consume(state, handle);
|
||||
// 2.AJ — clear guest-memory SignalState for guest-pointer auto-reset
|
||||
// dispatchers so the next refresh doesn't re-signal from stale memory.
|
||||
handle_consume_reciprocal_clear(state, mem, handle);
|
||||
ctx.gpr[3] = STATUS_SUCCESS;
|
||||
return;
|
||||
}
|
||||
@@ -5628,6 +5669,8 @@ fn do_wait_multiple(
|
||||
if wait_all {
|
||||
for &h in &handles {
|
||||
handle_consume(state, h);
|
||||
// 2.AJ — reciprocal guest-memory clear (see do_wait_single).
|
||||
handle_consume_reciprocal_clear(state, mem, h);
|
||||
}
|
||||
ctx.gpr[3] = STATUS_SUCCESS;
|
||||
} else if let Some((idx, &h)) = handles
|
||||
@@ -5636,6 +5679,8 @@ fn do_wait_multiple(
|
||||
.find(|&(_, &h)| handle_signaled(state, h))
|
||||
{
|
||||
handle_consume(state, h);
|
||||
// 2.AJ — reciprocal guest-memory clear (see do_wait_single).
|
||||
handle_consume_reciprocal_clear(state, mem, h);
|
||||
ctx.gpr[3] = idx as u64; // STATUS_WAIT_0 + idx
|
||||
} else {
|
||||
ctx.gpr[3] = STATUS_SUCCESS;
|
||||
|
||||
Reference in New Issue
Block a user