wip(probe): throwaway iterate-iterate-2AU-xaudio probe instrumentation
Uncommitted experimental probe code preserved for handoff. Per running memory these probes are inert/throwaway diagnostics, not production fixes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -5346,6 +5346,27 @@ fn emit_signal_match_if_waiters(
|
||||
crate::event_log::emit_signal_match(tid, cycle, signal_call, target_handle, n, &tids);
|
||||
}
|
||||
|
||||
/// AUDIT-2AU Option β: re-signal the XAudio render loop's frame-event
|
||||
/// pair, emulating the host XAudio2 OnBufferEnd callback firing once per
|
||||
/// audio period. Called from the round prologue gated by the same
|
||||
/// instruction-count audio cadence that drives `tick_instr`, so timing
|
||||
/// is deterministic (never host_ns). Mirrors `ke_set_event`'s signal +
|
||||
/// wake sequence for each captured event handle (see
|
||||
/// `do_wait_multiple` capture site + `XAudioState::frame_events`).
|
||||
pub fn pulse_xaudio_frame_events(state: &mut KernelState) {
|
||||
if state.xaudio.frame_events.is_empty() {
|
||||
return;
|
||||
}
|
||||
let events = state.xaudio.frame_events.clone();
|
||||
for h in events {
|
||||
if let Some(KernelObject::Event { signaled, .. }) = state.objects.get_mut(&h) {
|
||||
*signaled = true;
|
||||
emit_signal_match_if_waiters(state, "XAudioFramePulse", h);
|
||||
wake_eligible_waiters(state, h);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn ke_set_event(ctx: &mut PpcContext, mem: &GuestMemory, state: &mut KernelState) {
|
||||
// r3 = PKEVENT on Ke* (guest pointer). See `ensure_dispatcher_object`
|
||||
// for why we need the lazy-shadow step here.
|
||||
@@ -5652,6 +5673,30 @@ fn do_wait_multiple(
|
||||
Some(None) => None,
|
||||
None => None,
|
||||
};
|
||||
// AUDIT-2AU Option β: capture the XAudio render loop's frame-event
|
||||
// pair at the wait site. Sylpheed's render-driver thread (tid=11,
|
||||
// entry 0x824d2a94 = canary tid=4) blocks here on a WaitAny over two
|
||||
// guest-address Events (the "buffer ready" manual-reset + "frame
|
||||
// done" auto-reset pair). In canary these are signaled every audio
|
||||
// period by the host XAudio2 OnBufferEnd callback; in ours nothing
|
||||
// signals them after the first fast-path consumes the auto-reset
|
||||
// member, so the loop wedges forever (2.AL). Record the pair (no
|
||||
// hardcoded addresses) so the round-prologue audio-cadence ticker
|
||||
// re-signals them. Discriminator: a *multi*-handle WaitAny whose
|
||||
// members are all guest-address Events, with at least one XAudio
|
||||
// client registered — tid=2's lone guest-Event wait goes through
|
||||
// do_wait_single, so this won't catch it.
|
||||
if !wait_all
|
||||
&& handles.len() >= 2
|
||||
&& state.xaudio.any_registered()
|
||||
&& handles.iter().all(|&h| {
|
||||
h >= 0x8000_0000 && matches!(state.objects.get(&h), Some(KernelObject::Event { .. }))
|
||||
})
|
||||
{
|
||||
for &h in &handles {
|
||||
state.xaudio.note_frame_event(h);
|
||||
}
|
||||
}
|
||||
let current_ref = state.scheduler.current_ref();
|
||||
for &h in &handles {
|
||||
handle_enqueue_waiter(state, h, current_ref);
|
||||
|
||||
Reference in New Issue
Block a user