drm: drop to Unavailable when the background refresh finds no displays

The review asked for two things when the last CRTC disappears: push the empty
topology to consumers, and stop advertising the removed displays. Only the first
was done. The positive-TTL refresh still discarded an empty probe result and kept
the previous list, so on an idle host -- where there is no live stream to carry
the hotplug push -- enumeration kept reporting displays that were gone, exactly
as described. It now transitions to Unavailable on an empty result, matching the
hotplug path, while a failed probe (transient open/EACCES, not evidence the
displays are gone) keeps the verdict and only restamps it.
This commit is contained in:
Mariano Abad
2026-07-23 23:04:01 -03:00
parent 60518c9494
commit f71474ca4c

View File

@@ -805,11 +805,25 @@ fn refresh_available_async() {
let _in_flight = ProbeInFlightGuard;
let result = query_displays();
let mut st = DRM_STATE.lock().unwrap();
if let ProbeState::Available(since, list) = &mut *st {
*since = Instant::now();
if let Ok(fresh) = result {
if !fresh.is_empty() {
*list = fresh;
if !matches!(&*st, ProbeState::Available(..)) {
return;
}
match result {
Ok(fresh) if fresh.is_empty() => {
// No active CRTC left: every monitor is gone. Keeping the previous list here is
// what leaves enumeration advertising removed displays indefinitely on an idle
// host, where there is no live stream to deliver the hotplug push. Drop to
// Unavailable exactly as swap_available_displays does; a later probe restores
// Available when a monitor comes back.
log::info!("drm: refresh -> 0 displays, marking DRM unavailable");
*st = ProbeState::Unavailable(Instant::now());
}
Ok(fresh) => *st = ProbeState::Available(Instant::now(), fresh),
// A failed probe is not evidence that the displays are gone (a transient open or
// EACCES); keep the verdict, just restamp so we retry after the next TTL.
Err(_) => {
if let ProbeState::Available(since, _) = &mut *st {
*since = Instant::now();
}
}
}