atagen

monolith

public
Star0
Watch0

Commit 0e6ab4933125

tarball

atagen <boss@atagen.co>2026-10-17 05:09 UTC

3 files changed+51-19
monolith: stop waiting on imports when the import worker is gone

A failed send to a dead worker was dropped, leaving every later commit of that buffer behind a blocker nobody would release, so clients froze. Imports now fall back to the main thread. X11 configure failures are logged too, since a silent one leaves a window at a geometry the layout never chose.
Modified file: crates/monolith/src/import.rs+33 additions−13 deletions
@@ -7,6 +7,7 @@
77 use crate::state::State;
88 use monolith_render_vk::{DmabufImporter, ShmStager, StagedShm, VulkanTexture};
99 use smithay::backend::allocator::dmabuf::{Dmabuf, WeakDmabuf};
10+use smithay::backend::renderer::ImportDma;
1011 use smithay::reexports::calloop::LoopHandle;
1112 use smithay::reexports::calloop::channel::{Event, channel};
1213 use smithay::reexports::wayland_server::backend::ObjectId;
@@ -100,12 +101,22 @@ impl Imports {
100101 })
101102 }
102103
103- fn start(&mut self, buffer: &Dmabuf) -> &mut Waiters {
104- let jobs = &self.jobs;
105- self.dmabufs.entry(buffer.weak()).or_insert_with(|| {
106- let _ = jobs.send(Job::Dmabuf(buffer.clone()));
107- Waiters::default()
108- })
104+ /// None once the worker is gone, when the caller imports on the main
105+ /// thread instead of waiting on a job nobody will finish.
106+ fn start(&mut self, buffer: &Dmabuf) -> Option<&mut Waiters> {
107+ let key = buffer.weak();
108+ if !self.dmabufs.contains_key(&key) && !self.send(Job::Dmabuf(buffer.clone())) {
109+ return None;
110+ }
111+ Some(self.dmabufs.entry(key).or_default())
112+ }
113+
114+ fn send(&self, job: Job) -> bool {
115+ let sent = self.jobs.send(job).is_ok();
116+ if !sent {
117+ tracing::warn!("buffer import worker is gone");
118+ }
119+ sent
109120 }
110121 }
111122
@@ -116,7 +127,15 @@ impl State {
116127 let _ = notifier.successful::<State>();
117128 return;
118129 }
119- self.services.imports.start(buffer).notifiers.push(notifier);
130+ match self.services.imports.start(buffer) {
131+ Some(waiters) => waiters.notifiers.push(notifier),
132+ None => match self.renderer.import_dmabuf(buffer, None) {
133+ Ok(_) => {
134+ let _ = notifier.successful::<State>();
135+ }
136+ Err(_) => notifier.failed(),
137+ },
138+ }
120139 }
121140
122141 /// A blocker for a commit whose dmabuf the renderer has not imported yet.
@@ -124,7 +143,7 @@ impl State {
124143 if self.renderer.has_dmabuf(buffer) {
125144 return None;
126145 }
127- let waiters = self.services.imports.start(buffer);
146+ let waiters = self.services.imports.start(buffer)?;
128147 waiters.clients.push(client);
129148 Some(ImportBlocker(waiters.done.clone()))
130149 }
@@ -150,11 +169,12 @@ impl State {
150169 return None;
151170 }
152171 let imports = &mut self.services.imports;
153- let jobs = &imports.jobs;
154- let waiters = imports.shm.entry(buffer.id()).or_insert_with(|| {
155- let _ = jobs.send(Job::Shm(buffer.clone(), region));
156- Waiters::default()
157- });
172+ if !imports.shm.contains_key(&buffer.id())
173+ && !imports.send(Job::Shm(buffer.clone(), region))
174+ {
175+ return None;
176+ }
177+ let waiters = imports.shm.entry(buffer.id()).or_default();
158178 waiters.clients.push(client);
159179 Some(ImportBlocker(waiters.done.clone()))
160180 }
Modified file: crates/monolith/src/wm.rs+7 additions−3 deletions
@@ -210,9 +210,13 @@ pub fn configure(window: &Window, rect: Rect, kind: Kind, maximized: bool) -> bo
210210 }
211211 let (x0, y0) = (x as i32, y as i32);
212212 if let Some(x) = window.x11_surface() {
213- let _ = x.configure(Rectangle::new((x0, y0).into(), (w, h).into()));
214- let _ = x.set_fullscreen(kind == Kind::Fullscreen);
215- let _ = x.set_maximized(maximized && kind == Kind::Tiled);
213+ let geo = Rectangle::new((x0, y0).into(), (w, h).into());
214+ crate::xwayland::logged("configure", x.configure(geo));
215+ crate::xwayland::logged("fullscreen", x.set_fullscreen(kind == Kind::Fullscreen));
216+ crate::xwayland::logged(
217+ "maximize",
218+ x.set_maximized(maximized && kind == Kind::Tiled),
219+ );
216220 }
217221 if let Some(t) = window.toplevel() {
218222 t.with_pending_state(|s| {
Modified file: crates/monolith/src/xwayland.rs+11 additions−3 deletions
@@ -259,7 +259,7 @@ impl XwmHandler for State {
259259 fn unmapped_window(&mut self, _xwm: XwmId, window: X11Surface) {
260260 self.forget_x11(&window);
261261 if !window.is_override_redirect() {
262- let _ = window.set_mapped(false);
262+ logged("unmap", window.set_mapped(false));
263263 }
264264 }
265265
@@ -278,7 +278,7 @@ impl XwmHandler for State {
278278 _reorder: Option<Reorder>,
279279 ) {
280280 if self.x11_window_id(&window).is_some() {
281- let _ = window.configure(None);
281+ logged("configure", window.configure(None));
282282 return;
283283 }
284284 let mut geo = window.geometry();
@@ -286,7 +286,7 @@ impl XwmHandler for State {
286286 geo.loc.y = y.unwrap_or(geo.loc.y);
287287 geo.size.w = w.map_or(geo.size.w, |w| w as i32);
288288 geo.size.h = h.map_or(geo.size.h, |h| h as i32);
289- let _ = window.configure(geo);
289+ logged("configure", window.configure(geo));
290290 }
291291
292292 fn configure_notify(
@@ -397,3 +397,11 @@ impl State {
397397 }
398398 }
399399 }
400+
401+/// X11 requests fail when the window is already gone, which is routine, but
402+/// a failure on a live window means it never got the geometry we chose.
403+pub fn logged<E: std::fmt::Display>(what: &str, result: Result<(), E>) {
404+ if let Err(e) = result {
405+ tracing::debug!("X11 {what} failed: {e}");
406+ }
407+}