From 01b9cbed911a2b0aac07ace0eeb14cd4bd9605c4 Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Sat, 31 Oct 2026 09:53:37 -0700 Subject: [PATCH] fix(mac): take the rule-list locks in one order, so a rule check and a config load cannot deadlock BEHAVIOUR (lock order only). window.rs (should_manage rule check) took the regex list, then ignore, then manage, then floating; static_config.rs (apply_globals) took ignore, regex, manage, floating. Two threads, one checking a window and one loading the config, could each hold what the other waits for. Same defect as the KDE fix ef1d3ef0; the order is now the KDE one minus the lists macOS lacks: floating, (session floating), ignore, manage, (workspace rules), regex. Both sites acquire in that order and the order is documented at the statics in lib.rs. The other holders (process_event.rs floating -> regex, process_command.rs floating -> session floating, window_manager.rs workspace rules -> regex) already follow it; every other site takes a single rule list. Verified: macOS fake-CC type-check (tools/fast-check) PASS. Not verified: cannot run on Linux; a deadlock is not reproducible by reading anyway. Gate needed: none runnable here; hand check on a Mac (docs/dev/macos-handcheck.md): reload the config while windows open/close. --- komorebi-for-mac/komorebi/src/lib.rs | 4 ++++ komorebi-for-mac/komorebi/src/static_config.rs | 6 ++++-- komorebi-for-mac/komorebi/src/window.rs | 9 ++++++--- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/komorebi-for-mac/komorebi/src/lib.rs b/komorebi-for-mac/komorebi/src/lib.rs index 55cf64de..c71b0d16 100644 --- a/komorebi-for-mac/komorebi/src/lib.rs +++ b/komorebi-for-mac/komorebi/src/lib.rs @@ -122,6 +122,10 @@ lazy_static! { Arc::new(Mutex::new(HashMap::new())); static ref WORKSPACE_MATCHING_RULES: Arc>> = Arc::new(Mutex::new(Vec::new())); + // LOCK ORDER for the rule lists (as in the KDE tree, minus the lists macOS does not have): + // FLOATING_APPLICATIONS, SESSION_FLOATING_APPLICATIONS, IGNORE_IDENTIFIERS, MANAGE_IDENTIFIERS, + // WORKSPACE_MATCHING_RULES, REGEX_IDENTIFIERS. Take the ones you need in that order and never + // the other way round; a thread that does can deadlock with one that does not. static ref REGEX_IDENTIFIERS: Arc>> = Arc::new(Mutex::new(HashMap::new())); static ref MANAGE_IDENTIFIERS: Arc>> = Arc::new(Mutex::new(vec![])); diff --git a/komorebi-for-mac/komorebi/src/static_config.rs b/komorebi-for-mac/komorebi/src/static_config.rs index 5fe68137..3cd71ee4 100644 --- a/komorebi-for-mac/komorebi/src/static_config.rs +++ b/komorebi-for-mac/komorebi/src/static_config.rs @@ -545,16 +545,18 @@ impl ApplyGlobals for StaticConfig { // transparency_manager::TRANSPARENCY_ALPHA // .store(self.transparency_alpha.unwrap_or(200), Ordering::SeqCst); + // the order every other place takes them in (floating, ignore, manage, regex; see lib.rs): + // a thread that takes two in another order can wait for one that holds what it needs + let mut floating_applications = FLOATING_APPLICATIONS.lock(); let mut ignore_identifiers = IGNORE_IDENTIFIERS.lock(); - let mut regex_identifiers = REGEX_IDENTIFIERS.lock(); let mut manage_identifiers = MANAGE_IDENTIFIERS.lock(); + let mut regex_identifiers = REGEX_IDENTIFIERS.lock(); // let mut tray_and_multi_window_identifiers = TRAY_AND_MULTI_WINDOW_IDENTIFIERS.lock(); // let mut object_name_change_identifiers = OBJECT_NAME_CHANGE_ON_LAUNCH.lock(); // let mut object_name_change_title_ignore_list = OBJECT_NAME_CHANGE_TITLE_IGNORE_LIST.lock(); // let mut layered_identifiers = LAYERED_WHITELIST.lock(); // let mut transparency_blacklist = TRANSPARENCY_BLACKLIST.lock(); // let mut slow_application_identifiers = SLOW_APPLICATION_IDENTIFIERS.lock(); - let mut floating_applications = FLOATING_APPLICATIONS.lock(); // let mut no_titlebar_applications = NO_TITLEBAR.lock(); let mut titleless_applications = TITLELESS_APPLICATIONS.lock(); let mut tabbed_applications = TABBED_APPLICATIONS.lock(); diff --git a/komorebi-for-mac/komorebi/src/window.rs b/komorebi-for-mac/komorebi/src/window.rs index 90e80ad2..4b91c92b 100644 --- a/komorebi-for-mac/komorebi/src/window.rs +++ b/komorebi-for-mac/komorebi/src/window.rs @@ -1641,9 +1641,14 @@ fn window_is_eligible( } } + // Every place that holds two of the rule lists takes them in this order: floating, ignore, + // manage, regex (see the statics in lib.rs). A thread that takes two in another order can wait + // for one that holds what it needs, and both wait for ever. + let floating_identifiers = FLOATING_APPLICATIONS.lock(); + let ignore_identifiers = IGNORE_IDENTIFIERS.lock(); + let manage_identifiers = MANAGE_IDENTIFIERS.lock(); let regex_identifiers = REGEX_IDENTIFIERS.lock(); - let ignore_identifiers = IGNORE_IDENTIFIERS.lock(); let should_ignore = if let Some(rule) = should_act( title, exe_name, @@ -1658,7 +1663,6 @@ fn window_is_eligible( false }; - let manage_identifiers = MANAGE_IDENTIFIERS.lock(); let managed_override = if let Some(rule) = should_act( title, exe_name, @@ -1673,7 +1677,6 @@ fn window_is_eligible( false }; - let floating_identifiers = FLOATING_APPLICATIONS.lock(); if let Some(rule) = should_act( title, exe_name,