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

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) {