fix(dbus): Block on creation of zbus connection to avoid deadlock

A fix for the issue reported in
https://github.com/pop-os/cosmic-comp/pull/2450.

Using `block_on` in some places for zbus calls is fine (that's what
zbus's blocking API does; it has its own executor for background tasks),
but this is problematic with `async_once_cell`. If we also use that in
the calloop async executor.

I think ideally we should avoid blocking the main thread on any async
tasks, but for now we can just block in initialization here.
This commit is contained in:
Ian Douglas Scott 2026-06-09 07:51:44 -07:00 committed by Ashley Wulber
parent 94e9437c4e
commit 5153d497e7
3 changed files with 9 additions and 20 deletions

7
Cargo.lock generated
View file

@ -242,12 +242,6 @@ dependencies = [
"pin-project-lite",
]
[[package]]
name = "async-once-cell"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4288f83726785267c6f2ef073a3d83dc3f9b81464e9f99898240cced85fce35a"
[[package]]
name = "async-process"
version = "2.5.0"
@ -835,7 +829,6 @@ name = "cosmic-comp"
version = "1.0.0"
dependencies = [
"anyhow",
"async-once-cell",
"bitflags 2.11.0",
"calloop 0.14.4",
"cgmath",

View file

@ -83,7 +83,6 @@ logind-zbus = { version = "5.3.2", optional = true }
futures-executor = { version = "0.3.32" }
futures-util = "0.3.32"
cgmath = "0.18.0"
async-once-cell = "0.5.4"
[dependencies.id_tree]
branch = "feature/copy_clone"

View file

@ -26,19 +26,21 @@ pub struct DBusState(Rc<DBusStateInner>);
struct DBusStateInner {
evlh: LoopHandle<'static, State>,
executor: calloop::futures::Scheduler<()>,
session_conn: async_once_cell::OnceCell<zbus::Connection>,
system_conn: async_once_cell::OnceCell<zbus::Connection>,
session_conn: zbus::Result<zbus::Connection>,
system_conn: zbus::Result<zbus::Connection>,
a11y_keyboard_monitor: RefCell<Option<a11y_keyboard_monitor::A11yKeyboardMonitorState>>,
}
impl DBusState {
pub fn init(evlh: &LoopHandle<'static, State>) -> Self {
let (source, executor) = calloop::futures::executor().unwrap();
let session_conn = futures_executor::block_on(zbus::Connection::session());
let system_conn = futures_executor::block_on(zbus::Connection::system());
let state = Self(Rc::new(DBusStateInner {
evlh: evlh.clone(),
executor,
session_conn: async_once_cell::OnceCell::new(),
system_conn: async_once_cell::OnceCell::new(),
session_conn,
system_conn,
a11y_keyboard_monitor: RefCell::new(None),
}));
evlh.insert_source(source, |_, _, _| {}).unwrap();
@ -63,18 +65,13 @@ impl DBusState {
RefMut::filter_map(self.0.a11y_keyboard_monitor.borrow_mut(), |x| x.as_mut()).ok()
}
// TODO Lazy async init when we don't have anything blocking main thread
async fn session_conn(&self) -> zbus::Result<&zbus::Connection> {
self.0
.session_conn
.get_or_try_init(zbus::Connection::session())
.await
self.0.session_conn.as_ref().map_err(|err| err.clone())
}
async fn system_conn(&self) -> zbus::Result<&zbus::Connection> {
self.0
.system_conn
.get_or_try_init(zbus::Connection::system())
.await
self.0.system_conn.as_ref().map_err(|err| err.clone())
}
fn spawn(&self, fut: impl Future<Output = ()> + 'static) {