fix(windows-host): cross-plane IDD serialization, linger-expiry race, second-host guard
Batch C of the audit's medium tier (M7+M8+M9): - M7: GameStream sessions now run the same begin_idd_setup dance as punktfunk/1 before creating the shared monitor. A GS connect could previously ADD/reconfigure the monitor while a native session was mid-build (and vice versa), and its sealed-channel delivery replaced the native ring (newest-wins) — each plane could freeze the other. GS has no cooperative stop plumbing, so it registers a flag nobody reads: a later session signals it, waits the 3 s grace, then force-preempts — the intended handover. - M8: the linger-expiry teardown now runs UNDER the state lock. Running it outside let a concurrent acquire see Idle and ADD+isolate while the old monitor's pinger-join / CCD-restore / REMOVE were still in flight — a failed or de-isolated session exactly at the expiry boundary. A racing acquire now waits the few teardown seconds instead. Lock order stays state → device everywhere; the pinger takes only the device lock. - M9: a named mutex (Global\punktfunk-vdisplay-manager) makes a SECOND host process fail its vdisplay open loudly instead of firing a startup CLEAR_ALL that razes the live host's monitors mid-stream (the admin footgun the shared watchdog then masked). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -269,6 +269,23 @@ fn open_gs_virtual_source(
|
||||
));
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
vd.set_launch_command(app.and_then(|a| a.cmd.clone()));
|
||||
// Serialize with the punktfunk/1 plane's IDD-push setup dance (Goal-1 §2.5). A GameStream
|
||||
// connect used to skip it entirely, so it could ADD/reconfigure the shared monitor while a
|
||||
// native session was mid-build (and vice versa), and its sealed-channel delivery would replace
|
||||
// the native session's ring (newest-wins) — each plane could freeze the other. GameStream has
|
||||
// no cooperative stop-flag plumbing, so it registers a flag nobody reads: a LATER session that
|
||||
// preempts this one signals it, waits the 3 s release grace, then force-preempts the monitor —
|
||||
// this session then fails on capture and tears down cleanly (the intended handover).
|
||||
#[cfg(target_os = "windows")]
|
||||
let _idd_setup_guard = matches!(
|
||||
crate::session_plan::CaptureBackend::resolve(),
|
||||
crate::session_plan::CaptureBackend::IddPush
|
||||
)
|
||||
.then(|| {
|
||||
crate::vdisplay::manager::vdm().begin_idd_setup(std::sync::Arc::new(
|
||||
std::sync::atomic::AtomicBool::new(false),
|
||||
))
|
||||
});
|
||||
let vout = vd
|
||||
.create(punktfunk_core::Mode {
|
||||
width: cfg.width,
|
||||
|
||||
Reference in New Issue
Block a user