diff --git a/src/lib.rs b/src/lib.rs index 542162eb..f7282942 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,7 +16,7 @@ use smithay::{ }; use anyhow::{Context, Result}; -use state::{LastRefresh, State}; +use state::{BackendData, LastRefresh, State}; use std::{ env, ffi::OsString, @@ -222,19 +222,17 @@ pub fn run(hooks: crate::hooks::Hooks) -> Result<(), Box> { // Kiosk child exited with status Ok(Some(exit_status)) => { info!("Command exited with status {:?}", exit_status); - match exit_status.code() { - // Exiting with the same status as the kiosk child - Some(code) => process::exit(code), - // The kiosk child exited with signal, exiting with error - None => process::exit(1), - } + // Stop cleanly so surface threads are joined before exit() (signal -> 1). + state.common.kiosk_exit_code = Some(exit_status.code().unwrap_or(1)); + state.common.should_stop = true; } // Command still running Ok(None) => {} // Kiosk child disappeared, exiting with error Err(err) => { warn!(?err, "Failed to wait for command"); - process::exit(1); + state.common.kiosk_exit_code = Some(1); + state.common.should_stop = true; } } } @@ -245,10 +243,32 @@ pub fn run(hooks: crate::hooks::Hooks) -> Result<(), Box> { let _ = child.kill(); } + let kiosk_exit_code = state.common.kiosk_exit_code; + + // Join surface threads before exit() so no thread is mid-eglCreateSync when + // Mesa's atexit handlers run and corrupt the heap (issue #2375). Safe here + // because the event loop has stopped; an unconditional join in Surface::Drop + // would instead deadlock against apply_config_for_outputs. + if let BackendData::Kms(kms) = &mut state.backend { + // Release master first so the surface drop path skips its blocking commit. + for device in kms.drm_devices.values_mut() { + device.drm.pause(); + } + for device in kms.drm_devices.values_mut() { + for (_, surface) in device.inner.surfaces.drain() { + surface.drop_and_join(); + } + } + } + // drop eventloop & state before logger std::mem::drop(event_loop); std::mem::drop(state); + if let Some(code) = kiosk_exit_code { + process::exit(code); + } + Ok(()) } diff --git a/src/state.rs b/src/state.rs index 21cbb400..ce546505 100644 --- a/src/state.rs +++ b/src/state.rs @@ -244,6 +244,7 @@ pub struct Common { pub clock: Clock, pub startup_done: Arc, pub should_stop: bool, + pub kiosk_exit_code: Option, pub gesture_state: Option, @@ -754,6 +755,7 @@ impl State { clock, startup_done: Arc::new(AtomicBool::new(false)), should_stop: false, + kiosk_exit_code: None, gesture_state: None, kiosk_child: None,