From d40c304324d1af8ae5a1cb6132b619adbd19b3be Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Tue, 8 Apr 2025 16:14:33 -0700 Subject: [PATCH] fix(borders): avoid deadlock on state hashmaps This commit addresses a deadlock on WINDOW_BORDERS which can occur under load, particularly when switching workspaces. When switching workspaces using the komorebi-bar, RetileWithResizeDimensions is also called, which calls border_manager::destroy_all_borders. At the same time, border_manager::window_border is called when hiding borders from the previous workspace. Both of these functions try to take locks on WINDOWS_BORDERS and BORDER_STATE. border_manager::window_border is called in a new thread by hide_border, so if this has not finished with the lock by the time destroy_all_borders requests it, we get stuck in a deadlock. The changes in this commit ensure that the BORDER_STATE lock is dropped as early as possible in destroy_all_borders, and that we are not holding the WINDOWS_BORDERS lock in window_border while trying to get the BORDER_STATE lock to look up BorderInfo. The logs which show the initial deadlock being detected: 2025-04-08T22:49:37.641888Z WARN komorebi::process_command: could not acquire window manager lock, not processing message: FocusWorkspaceNumber 2025-04-08T22:49:38.294952Z WARN komorebi::process_command: could not acquire window manager lock, not processing message: FocusWorkspaceNumber 2025-04-08T22:49:39.225645Z ERROR komorebi: 1 deadlocks detected 2025-04-08T22:49:39.225826Z ERROR komorebi: deadlock #0 2025-04-08T22:49:39.225950Z ERROR komorebi: thread id: 9896 2025-04-08T22:49:39.226072Z ERROR komorebi: 0: 0x7ff68fd33dec - backtrace::backtrace::dbghelp64::trace at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\backtrace-0.3.71\src\backtrace\dbghelp64.rs:99 backtrace::backtrace::trace_unsynchronized at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\backtrace-0.3.71\src\backtrace\mod.rs:66 1: 0x7ff68fd33c87 - backtrace::backtrace::trace at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\backtrace-0.3.71\src\backtrace\mod.rs:53 2: 0x7ff68fd3c03e - backtrace::capture::Backtrace::create at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\backtrace-0.3.71\src\capture.rs:193 3: 0x7ff68fd3bfae - backtrace::capture::Backtrace::new at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\backtrace-0.3.71\src\capture.rs:158 4: 0x7ff68f937b54 - parking_lot_core::parking_lot::deadlock_impl::on_unpark at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\parking_lot_core-0.9.10\src\parking_lot.rs:1211 5: 0x7ff68f921f0e - parking_lot_core::parking_lot::deadlock::on_unpark at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\parking_lot_core-0.9.10\src\parking_lot.rs:1144 6: 0x7ff68f92bf88 - parking_lot_core::parking_lot::park::closure$0 at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\parking_lot_core-0.9.10\src\parking_lot.rs:637 7: 0x7ff68f92a777 - parking_lot_core::parking_lot::with_thread_data at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\parking_lot_core-0.9.10\src\parking_lot.rs:207 parking_lot_core::parking_lot::park at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\parking_lot_core-0.9.10\src\parking_lot.rs:600 8: 0x7ff68f926fa0 - parking_lot::raw_mutex::RawMutex::lock_slow at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\parking_lot-0.12.3\src\raw_mutex.rs:262 9: 0x7ff68f1daac6 - parking_lot::raw_mutex::impl$0::lock at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\parking_lot-0.12.3\src\raw_mutex.rs:72 10: 0x7ff68ef05eb3 - lock_api::mutex::Mutex >::lock > at komorebi\src\process_command.rs:918 13: 0x7ff68ef1fdcf - komorebi::process_command::read_commands_uds at komorebi\src\process_command.rs:2292 14: 0x7ff68f231eb5 - komorebi::process_command::listen_for_commands::closure$0::closure$0::closure$0 at komorebi\src\process_command.rs:123 15: 0x7ff68f32bcf3 - core::hint::black_box at C:\Users\LGUG2Z\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\core\src\hint.rs:477 std::sys::backtrace::__rust_begin_short_backtrace > at C:\Users\LGUG2Z\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\std\src\sys\backtrace.rs:152 16: 0x7ff68f00d1b4 - std::thread::impl$0::spawn_unchecked_::closure$1::closure$0 > at C:\Users\LGUG2Z\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\std\src\thread\mod.rs:559 17: 0x7ff68f356ea1 - core::panic::unwind_safe::impl$25::call_once,std::thread::impl$0::spawn_unchecked_::closure$1::closure_env$0 > > at C:\Users\LGUG2Z\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\core\src\panic\unwind_safe.rs:272 18: 0x7ff68f1d1e00 - std::panicking::try::do_call > >,tuple$<> > at C:\Users\LGUG2Z\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\std\src\panicking.rs:587 19: 0x7ff68f0102b3 - std::thread::impl$7::drop::closure$0,eyre::Report> > > 20: 0x7ff68f007be7 - std::panicking::try at C:\Users\LGUG2Z\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\std\src\panicking.rs:550 std::panic::catch_unwind at C:\Users\LGUG2Z\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\std\src\panic.rs:358 std::thread::impl$0::spawn_unchecked_::closure$1 > at C:\Users\LGUG2Z\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\std\src\thread\mod.rs:557 21: 0x7ff68ecfeb8e - core::ops::function::FnOnce::call_once >,tuple$<> > at C:\Users\LGUG2Z\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\core\src\ops\function.rs:250 22: 0x7ff68fe84f1d - alloc::boxed::impl$28::call_once at /rustc/05f9846f893b09a1be1fc8560e33fc3c815cfecb/library\alloc\src\boxed.rs:1976 alloc::boxed::impl$28::call_once at /rustc/05f9846f893b09a1be1fc8560e33fc3c815cfecb/library\alloc\src\boxed.rs:1976 std::sys::pal::windows::thread::impl$0::new::thread_start at /rustc/05f9846f893b09a1be1fc8560e33fc3c815cfecb/library\std\src\sys\pal\windows\thread.rs:56 23: 0x7ff8ef27257d - BaseThreadInitThunk 24: 0x7ff8f042af28 - RtlUserThreadStart 2025-04-08T22:49:39.228617Z ERROR komorebi: thread id: 62364 2025-04-08T22:49:39.228731Z ERROR komorebi: 0: 0x7ff68fd33dec - backtrace::backtrace::dbghelp64::trace at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\backtrace-0.3.71\src\backtrace\dbghelp64.rs:99 backtrace::backtrace::trace_unsynchronized at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\backtrace-0.3.71\src\backtrace\mod.rs:66 1: 0x7ff68fd33c87 - backtrace::backtrace::trace at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\backtrace-0.3.71\src\backtrace\mod.rs:53 2: 0x7ff68fd3c03e - backtrace::capture::Backtrace::create at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\backtrace-0.3.71\src\capture.rs:193 3: 0x7ff68fd3bfae - backtrace::capture::Backtrace::new at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\backtrace-0.3.71\src\capture.rs:158 4: 0x7ff68f937b54 - parking_lot_core::parking_lot::deadlock_impl::on_unpark at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\parking_lot_core-0.9.10\src\parking_lot.rs:1211 5: 0x7ff68f921f0e - parking_lot_core::parking_lot::deadlock::on_unpark at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\parking_lot_core-0.9.10\src\parking_lot.rs:1144 6: 0x7ff68f92bf88 - parking_lot_core::parking_lot::park::closure$0 at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\parking_lot_core-0.9.10\src\parking_lot.rs:637 7: 0x7ff68f92a777 - parking_lot_core::parking_lot::with_thread_data at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\parking_lot_core-0.9.10\src\parking_lot.rs:207 parking_lot_core::parking_lot::park at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\parking_lot_core-0.9.10\src\parking_lot.rs:600 8: 0x7ff68f926fa0 - parking_lot::raw_mutex::RawMutex::lock_slow at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\parking_lot-0.12.3\src\raw_mutex.rs:262 9: 0x7ff68f1daac6 - parking_lot::raw_mutex::impl$0::lock at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\parking_lot-0.12.3\src\raw_mutex.rs:72 10: 0x7ff68ef05d93 - lock_api::mutex::Mutex,std::hash::random::RandomState> >::lock > >::and_then,komorebi::border_manager::BorderInfo,komorebi::border_manager::window_border::closure_env$0> at C:\Users\LGUG2Z\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\core\src\option.rs:1452 13: 0x7ff68ef06339 - komorebi::border_manager::window_border at komorebi\src\border_manager\mod.rs:108 --- komorebi/src/border_manager/mod.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/komorebi/src/border_manager/mod.rs b/komorebi/src/border_manager/mod.rs index a35872af..3cd66255 100644 --- a/komorebi/src/border_manager/mod.rs +++ b/komorebi/src/border_manager/mod.rs @@ -105,11 +105,10 @@ fn event_rx() -> Receiver { } pub fn window_border(hwnd: isize) -> Option { - WINDOWS_BORDERS.lock().get(&hwnd).and_then(|id| { - BORDER_STATE.lock().get(id).map(|b| BorderInfo { - border_hwnd: b.hwnd, - window_kind: b.window_kind, - }) + let id = WINDOWS_BORDERS.lock().get(&hwnd)?.clone(); + BORDER_STATE.lock().get(&id).map(|b| BorderInfo { + border_hwnd: b.hwnd, + window_kind: b.window_kind, }) } @@ -136,6 +135,8 @@ pub fn destroy_all_borders() -> color_eyre::Result<()> { let _ = destroy_border(border); } + drop(borders); + WINDOWS_BORDERS.lock().clear(); let mut remaining_hwnds = vec![];