git.lucas.co / cce-compositor
Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git

commit9976f40fab78a8bb7fa97d7c597b768b229bf62f
parent19cb24b8b4
authorLucas Galante <[email protected]>
date2026-06-22 21:32
fix: resolve Xwayland startup failure by implementing proper SIGCHLD signal handling

 src/server/process.rs |  3 ---
 src/server/server.rs  | 11 +++++++++++
 2 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/src/server/process.rs b/src/server/process.rs
index 244fb62..97b7a75 100644
--- a/src/server/process.rs
+++ b/src/server/process.rs
@@ -9,11 +9,8 @@ static ORIGINAL_RLIMIT: Mutex<Option<libc::rlimit>> = Mutex::new(None);
 pub fn setup() {
     // Ignore SIGPIPE so we don't get killed when writing to a socket that
     // has had its read end closed by another process.
-    // Also ignore SIGCHLD to automatically reap terminated child processes
-    // and prevent them from becoming zombies.
     unsafe {
         libc::signal(libc::SIGPIPE, libc::SIG_IGN);
-        libc::signal(libc::SIGCHLD, libc::SIG_IGN);
     }
 
     // Most unix systems have a default limit of 1024 file descriptors.
diff --git a/src/server/server.rs b/src/server/server.rs
index 4df2c82..036381a 100644
--- a/src/server/server.rs
+++ b/src/server/server.rs
@@ -220,6 +220,7 @@ pub struct Server {
     pub wl_server: *mut ffi::wl_display,
     pub sigint_source: *mut ffi::wl_event_source,
     pub sigterm_source: *mut ffi::wl_event_source,
+    pub sigchld_source: *mut ffi::wl_event_source,
     // pub fixes: *mut ffi::wlr_fixes,
     pub backend: *mut ffi::wlr_backend,
     pub session: *mut ffi::wlr_session,
@@ -290,6 +291,12 @@ unsafe extern "C" fn terminate(_signum: std::os::raw::c_int, data: *mut std::ffi
     0
 }
 
+unsafe extern "C" fn handle_sigchld(_signum: std::os::raw::c_int, _data: *mut std::ffi::c_void) -> std::os::raw::c_int {
+    let mut status = 0;
+    while libc::waitpid(-1, &mut status, libc::WNOHANG) > 0 {}
+    0
+}
+
 unsafe extern "C" fn handle_renderer_lost(listener: *mut ffi::wl_listener, _data: *mut std::ffi::c_void) {
     let _server = container_of!(listener, Server, renderer_lost);
     log::info!("received GPU reset event");
@@ -464,6 +471,7 @@ impl Server {
 
             self.sigint_source = ffi::wl_event_loop_add_signal(loop_, libc::SIGINT, Some(terminate), wl_server as *mut _);
             self.sigterm_source = ffi::wl_event_loop_add_signal(loop_, libc::SIGTERM, Some(terminate), wl_server as *mut _);
+            self.sigchld_source = ffi::wl_event_loop_add_signal(loop_, libc::SIGCHLD, Some(handle_sigchld), wl_server as *mut _);
 
             let mut session: *mut ffi::wlr_session = ptr::null_mut();
             let backend = ffi::wlr_backend_autocreate(loop_, &mut session);
@@ -776,6 +784,9 @@ impl Server {
             log::info!("[deinit] removing server listeners");
             ffi::wl_event_source_remove(self.sigint_source);
             ffi::wl_event_source_remove(self.sigterm_source);
+            if !self.sigchld_source.is_null() {
+                ffi::wl_event_source_remove(self.sigchld_source);
+            }
 
             wl_listener_remove(&mut self.renderer_lost);
             wl_listener_remove(&mut self.new_xdg_toplevel);