mirror of
https://github.com/rustdesk/rustdesk.git
synced 2026-09-08 05:20:59 +03:00
drm: do not let a stale availability probe overwrite a newer verdict
query_displays() in the background refresh runs unlocked because it is slow, so a hotplug push can publish a newer verdict while it is in flight; the refresh then overwrote it with its own older result. Harmless while it only replaced the list, but the previous commit made an empty result drop to Unavailable, so a probe that started while the monitors were gone could disable DRM on a host whose monitor had since come back. The refresh now samples the stamp of the verdict it is refreshing and publishes only if that stamp is still current. Every publish stamps a fresh Instant, so an unchanged stamp means nothing republished in between -- equivalent to threading a revision counter through every publish site, without having to keep all of them in sync.
This commit is contained in:
@@ -799,14 +799,32 @@ fn refresh_available_async() {
|
||||
// clears on every exit -- normal return, a panic in query_displays, or a poisoned DRM_STATE. If
|
||||
// thread creation itself fails the closure never runs, so that path releases the guard explicitly
|
||||
// below. Either way a one-off failure cannot leave the guard stuck true and freeze future probes.
|
||||
// Stamp of the verdict we are refreshing. query_displays() below runs UNLOCKED because it is
|
||||
// slow, so a hotplug push (swap_available_displays) can publish a newer verdict while we probe.
|
||||
// We compare this stamp before publishing so an older probe cannot overwrite it -- which matters
|
||||
// now that an empty result drops to Unavailable: a probe that started while the monitors were
|
||||
// gone would otherwise disable DRM on a host whose monitor has since come back. Every publish
|
||||
// stamps a fresh Instant, so an unchanged stamp means nothing republished in between (this is
|
||||
// why the check is a stamp comparison rather than a separate revision counter threaded through
|
||||
// every publish site).
|
||||
let sampled = match &*DRM_STATE.lock().unwrap() {
|
||||
ProbeState::Available(since, _) => *since,
|
||||
_ => {
|
||||
DRM_PROBE_IN_FLIGHT.store(false, Ordering::Release);
|
||||
return;
|
||||
}
|
||||
};
|
||||
let spawned = std::thread::Builder::new()
|
||||
.name("drm-avail-refresh".into())
|
||||
.spawn(|| {
|
||||
.spawn(move || {
|
||||
let _in_flight = ProbeInFlightGuard;
|
||||
let result = query_displays();
|
||||
let mut st = DRM_STATE.lock().unwrap();
|
||||
if !matches!(&*st, ProbeState::Available(..)) {
|
||||
return;
|
||||
match &*st {
|
||||
ProbeState::Available(since, _) if *since == sampled => {}
|
||||
// Someone republished while we probed (a hotplug push, or a cold probe). Their
|
||||
// verdict is newer than ours; leave it alone.
|
||||
_ => return,
|
||||
}
|
||||
match result {
|
||||
Ok(fresh) if fresh.is_empty() => {
|
||||
|
||||
Reference in New Issue
Block a user