From c5eea458b4d4719f8e1263dd6d189e35a77c8d1b Mon Sep 17 00:00:00 2001 From: enricobuehler Date: Sun, 9 Aug 2026 00:40:54 +0200 Subject: [PATCH] =?UTF-8?q?fix(windows/cursor):=20gate=20the=20between-ses?= =?UTF-8?q?sion=20recycle=20off=20=E2=80=94=20calling=20it=20from=20ADD=20?= =?UTF-8?q?deadlocks?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ADD path holds the manager 'device' mutex, and invalidate_cached_device takes it. Its own doc says it must not be called from inside that mutex. Calling it there deadlocked the session: on .173 the ADD stopped after SET_RENDER_ADAPTER, no monitor was created, and the client reported 'no frames received'. The mechanism itself is sound and measured — recycling the driver's WUDFHost clears the declare (pid 3872 -> 19932, adapter_luid 0x8ed607 -> 0x1a8f6ca, cursor_excluded true -> false, next session streamed normally). What is missing is a call site that runs OUTSIDE that mutex and is still on every session's path; the handshake site tried earlier is not reached on this host. Off unless PUNKTFUNK_CURSOR_RECYCLE=1. A session that self-composites is the old behaviour; a deadlocked one is a regression, and the tree should not carry that while the call site is unsolved. --- .../src/vdisplay/windows/pf_vdisplay.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/crates/pf-vdisplay/src/vdisplay/windows/pf_vdisplay.rs b/crates/pf-vdisplay/src/vdisplay/windows/pf_vdisplay.rs index 96ae47fe..7a5b342d 100644 --- a/crates/pf-vdisplay/src/vdisplay/windows/pf_vdisplay.rs +++ b/crates/pf-vdisplay/src/vdisplay/windows/pf_vdisplay.rs @@ -910,7 +910,19 @@ impl VdisplayDriver for PfVdisplayDriver { // this monitor is added. The ADD path is the only place guaranteed to see every session // (the handshake call site this replaced sat in a `match (source, compositor)` arm that is // not taken on this host, so it never ran). - if !hw_cursor { + // ⚠ DISABLED BY DEFAULT — opt in with PUNKTFUNK_CURSOR_RECYCLE=1. + // + // The MECHANISM is proven (recycling the driver host clears the declare: measured pid + // 3872→19932, adapter_luid 0x8ed607→0x1a8f6ca, cursor_excluded true→false, next session + // streamed fine). What is NOT solved is calling it from HERE: `invalidate_cached_device` + // takes the manager `device` mutex, which this ADD path already holds, so the session + // DEADLOCKS — observed on .173, the ADD stops after SET_RENDER_ADAPTER and the client gets + // "no frames received". Its own doc warns about exactly this. + // + // The fix is a call site that runs OUTSIDE the mutex and still on every session's path; + // the handshake site tried before is not reached on this host. Until then this stays off: + // a session that self-composites is the old behaviour, a deadlocked one is a regression. + if !hw_cursor && std::env::var("PUNKTFUNK_CURSOR_RECYCLE").is_ok_and(|v| v == "1") { clean_cursor_for_next_session(false); } let session_id = next_session_id();