Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git
fix: resolve core dump on compositor shutdown by unregistering cursor event listeners and detaching devices from seat
src/server/cursor.rs | 6 ++++++
src/server/input_manager.rs | 36 ++++++++++++++++++++++++++++++++---
src/server/server.rs | 46 +++++++++++++++++++++++++++++++++++----------
3 files changed, 75 insertions(+), 13 deletions(-)
diff --git a/src/server/cursor.rs b/src/server/cursor.rs
index 0458992..6931d84 100644
--- a/src/server/cursor.rs
+++ b/src/server/cursor.rs
@@ -268,6 +268,12 @@ impl Cursor {
}
pub unsafe fn deinit(&mut self) {
+ wl_listener_remove(&mut self.motion_listener);
+ wl_listener_remove(&mut self.motion_absolute_listener);
+ wl_listener_remove(&mut self.button_listener);
+ wl_listener_remove(&mut self.axis_listener);
+ wl_listener_remove(&mut self.frame_listener);
+
wl_listener_remove(&mut self.tablet_tool_axis_listener);
wl_listener_remove(&mut self.tablet_tool_proximity_listener);
wl_listener_remove(&mut self.tablet_tool_tip_listener);
diff --git a/src/server/input_manager.rs b/src/server/input_manager.rs
index 54f8d54..98f1c45 100644
--- a/src/server/input_manager.rs
+++ b/src/server/input_manager.rs
@@ -103,7 +103,9 @@ impl InputManager {
}
pub unsafe fn deinit(&mut self) {
+ log::info!("[deinit] InputManager::deinit started");
if !self.global.is_null() {
+ log::info!("[deinit] destroying input manager global");
ffi::wl_global_destroy(self.global);
self.global = std::ptr::null_mut();
}
@@ -117,14 +119,42 @@ impl InputManager {
curr = next;
}
- if !self.default_seat.is_null() {
- Seat::destroy(self.default_seat);
- self.default_seat = std::ptr::null_mut();
+ // Detach all devices from their seats and set their seat pointer to null
+ // so they do not attempt to access a freed seat during backend destruction.
+ log::info!("[deinit] detaching devices");
+ let devices_head = &mut self.devices as *mut ffi::wl_list as *mut WlList;
+ let mut curr_dev = (*devices_head).next;
+ while curr_dev != devices_head {
+ let next_dev = (*curr_dev).next;
+ let device = crate::container_of!(curr_dev, crate::input_device::InputDevice, link);
+ if !(*device).seat.is_null() {
+ log::info!("[deinit] detaching device from seat");
+ (*(*device).seat).detach_device(device);
+ (*device).seat = std::ptr::null_mut();
+ }
+ curr_dev = next_dev;
+ }
+
+ // Destroy all seats
+ log::info!("[deinit] destroying seats");
+ let seats_head = &mut self.seats as *mut ffi::wl_list as *mut WlList;
+ let mut curr_seat = (*seats_head).next;
+ while curr_seat != seats_head {
+ let next_seat = (*curr_seat).next;
+ let seat = crate::container_of!(curr_seat, Seat, link);
+ log::info!("[deinit] calling Seat::destroy for {:?}", (*seat).wlr_seat);
+ Seat::destroy(seat);
+ curr_seat = next_seat;
}
+ self.default_seat = std::ptr::null_mut();
+ log::info!("[deinit] seats destroyed");
+
+ log::info!("[deinit] removing input manager listeners");
wl_listener_remove(&mut self.new_input_listener);
wl_listener_remove(&mut self.new_text_input);
wl_listener_remove(&mut self.new_input_method);
wl_listener_remove(&mut self.new_virtual_pointer_listener);
+ log::info!("[deinit] InputManager::deinit finished");
}
}
diff --git a/src/server/server.rs b/src/server/server.rs
index 42e377a..692998e 100644
--- a/src/server/server.rs
+++ b/src/server/server.rs
@@ -728,6 +728,33 @@ impl Server {
pub fn deinit(&mut self) {
unsafe {
+ log::info!("[deinit] Server::deinit started");
+ // 1. Terminate all client connections first
+ log::info!("[deinit] wl_display_destroy_clients started");
+ ffi::wl_display_destroy_clients(self.wl_server);
+ log::info!("[deinit] wl_display_destroy_clients finished");
+
+ // 2. Deinitialize subcomponents while backend, renderer, allocator, and display are valid
+ log::info!("[deinit] self.om.deinit started");
+ self.om.deinit();
+ log::info!("[deinit] self.om.deinit finished");
+
+ log::info!("[deinit] self.input_manager.deinit started");
+ self.input_manager.deinit();
+ log::info!("[deinit] self.input_manager.deinit finished");
+
+ log::info!("[deinit] deinitializing other subcomponents");
+ self.idle_inhibit_manager.deinit();
+ self.lock_manager.deinit();
+ self.layer_shell.deinit();
+ self.inspector.deinit();
+ self.xkb_bindings.deinit();
+ self.libinput_config.deinit();
+ self.xkb_config.deinit();
+ log::info!("[deinit] other subcomponents deinitialized");
+
+ // 3. Remove signal listeners registered directly by the server
+ log::info!("[deinit] removing server listeners");
ffi::wl_event_source_remove(self.sigint_source);
ffi::wl_event_source_remove(self.sigterm_source);
@@ -736,27 +763,26 @@ impl Server {
wl_listener_remove(&mut self.new_toplevel_decoration);
wl_listener_remove(&mut self.request_activate);
wl_listener_remove(&mut self.request_set_cursor_shape);
- // wl_listener_remove(&mut self.toplevel_capture_request);
+ // 4. Destroy Xwayland if active
if !self.xwayland.is_null() {
wl_listener_remove(&mut self.new_xsurface);
ffi::wlr_xwayland_destroy(self.xwayland);
}
+ log::info!("[deinit] server listeners removed");
- ffi::wl_display_destroy_clients(self.wl_server);
+ // 5. Destroy wlroots core hardware interfaces
+ log::info!("[deinit] destroying backend");
ffi::wlr_backend_destroy(self.backend);
-
+ log::info!("[deinit] destroying renderer");
ffi::wlr_renderer_destroy(self.renderer);
+ log::info!("[deinit] destroying allocator");
ffi::wlr_allocator_destroy(self.allocator);
- self.om.deinit();
- self.input_manager.deinit();
- self.idle_inhibit_manager.deinit();
- self.lock_manager.deinit();
- self.layer_shell.deinit();
- self.inspector.deinit();
-
+ // 6. Finally, destroy the display
+ log::info!("[deinit] destroying display");
ffi::wl_display_destroy(self.wl_server);
+ log::info!("[deinit] Server::deinit finished successfully");
}
}
}