Iterate-2.BE Path β: tick vsync from coord_idle_advance
The iterate-2.BE host-driven synchronous ISR dispatcher relies on
something queueing v-syncs. In lockstep that's `tick_vsync_instr`,
called from `coord_pre_round` per round. If the scheduler stalls into
`coord_idle_advance` (no Ready threads), the instruction counter
freezes — the accumulator stops incrementing, the ticker stops
queueing, and the dispatcher is left starved for the duration of the
idle wait.
Tick `tick_vsync_wallclock` at the top of `coord_idle_advance` so
v-syncs keep firing on host time even when the guest scheduler is
parked. The dispatcher in the outer loop drains whatever we queue on
the next iteration. Same MMIO `D1MODE_VBLANK_VLINE_STATUS` bit-set as
the production path.
Note: empirically in Sylpheed at 50M/500M instruction horizons,
`coord_idle_advance` is never reached (tids 9/10/12 stay Ready through
the early-boot deadlock), so this commit doesn't move
`gpu.interrupt.delivered{source=0}` off 54 for this title at these
horizons. It is the correct fix for the documented starvation pattern
and will activate as soon as the kernel reaches a state where Ready
threads drop to zero with timers/waits pending.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2016,6 +2016,24 @@ fn coord_idle_advance(
|
||||
shutdown: &Option<std::sync::Arc<std::sync::atomic::AtomicBool>>,
|
||||
stats: &ExecStats,
|
||||
) -> RoundCtl {
|
||||
// Path β (iterate-2.BE follow-up): when the scheduler has no Ready
|
||||
// threads, `coord_pre_round`'s instruction-count vsync ticker stops
|
||||
// advancing (instruction_count is frozen). That starves the
|
||||
// host-driven graphics ISR dispatcher: queue stays empty, no
|
||||
// deliveries occur, and the very stall we're trying to break out of
|
||||
// gets worse. Tick vsync from wallclock here unconditionally — it's
|
||||
// a host-clock read, independent of instruction count, and the
|
||||
// dispatcher in the outer loop will drain whatever we queue on the
|
||||
// next pass. Mirrors the `--parallel` ticker choice in
|
||||
// `coord_pre_round` (`tick_vsync_wallclock` branch).
|
||||
if kernel.interrupts.tick_vsync_wallclock() {
|
||||
use std::sync::atomic::Ordering;
|
||||
let mmio = kernel.gpu.mmio();
|
||||
let prev = mmio.d1mode_vblank_vline_status.load(Ordering::Relaxed);
|
||||
mmio.d1mode_vblank_vline_status
|
||||
.store(prev | 0x1, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
let next_timer = kernel.earliest_timer_deadline();
|
||||
let next_wait = kernel.scheduler.earliest_wait_deadline();
|
||||
let target = match (next_timer, next_wait) {
|
||||
|
||||
Reference in New Issue
Block a user