diff --git a/crates/crashes/src/crashes.rs b/crates/crashes/src/crashes.rs index 5d3fc954d30..357119e8589 100644 --- a/crates/crashes/src/crashes.rs +++ b/crates/crashes/src/crashes.rs @@ -182,6 +182,7 @@ pub struct CrashServer { active_gpu: Mutex>, user_info: Mutex>, abort_message_location: Mutex>, + shutdown: Arc, has_connection: Arc, logs_dir: PathBuf, } @@ -255,6 +256,11 @@ pub fn set_user_info(crash_client: &Arc, info: UserInfo) { send_crash_server_message(crash_client, CrashServerMessage::UserInfo(info)); } +/// Requests an orderly exit from the crash-handler sidecar. +pub fn shutdown_crash_handler(crash_client: &Arc) { + send_crash_server_message(crash_client, CrashServerMessage::Shutdown); +} + #[derive(Serialize, Deserialize, Debug)] enum CrashServerMessage { Init(InitCrashHandler), @@ -262,6 +268,7 @@ enum CrashServerMessage { GPUInfo(GpuSpecs), UserInfo(UserInfo), AbortMessageLocation(AbortMessageLocation), + Shutdown, } /// glibc records the diagnostic it prints just before aborting (malloc integrity @@ -464,6 +471,9 @@ impl minidumper::ServerHandler for CrashServer { CrashServerMessage::AbortMessageLocation(location) => { self.abort_message_location.lock().replace(location); } + CrashServerMessage::Shutdown => { + self.shutdown.store(true, Ordering::SeqCst); + } } } @@ -668,6 +678,7 @@ pub fn crash_server(socket: &Path, logs_dir: PathBuf) { panic_info: Mutex::default(), user_info: Mutex::default(), abort_message_location: Mutex::default(), + shutdown: shutdown.clone(), has_connection, active_gpu: Mutex::default(), logs_dir, @@ -682,6 +693,44 @@ pub fn crash_server(socket: &Path, logs_dir: PathBuf) { mod tests { use super::*; + #[test] + fn shutdown_stops_crash_server() { + let unique = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .expect("system clock is before the Unix epoch") + .as_nanos(); + let socket = PathBuf::from(format!( + "crashes-shutdown-test-{}-{unique}", + std::process::id() + )); + let logs_dir = std::env::temp_dir(); + let (server_stopped_tx, server_stopped_rx) = std::sync::mpsc::channel(); + let server_socket = socket.clone(); + std::thread::spawn(move || { + crash_server(&server_socket, logs_dir); + server_stopped_tx + .send(()) + .expect("test receiver should remain connected"); + }); + + let client = Arc::new( + (0..100) + .find_map(|_| { + let client = Client::with_name(SocketName::Path(&socket)).ok(); + if client.is_none() { + std::thread::sleep(Duration::from_millis(10)); + } + client + }) + .expect("crash server did not start"), + ); + + shutdown_crash_handler(&client); + server_stopped_rx + .recv_timeout(Duration::from_secs(2)) + .expect("crash server did not stop"); + } + #[test] fn abort_message_read_len_requires_page_rounded_total() { assert_eq!(abort_message_read_len(0), None); diff --git a/crates/gpui_windows/src/events.rs b/crates/gpui_windows/src/events.rs index 1bd18493d0b..e700cb0fc51 100644 --- a/crates/gpui_windows/src/events.rs +++ b/crates/gpui_windows/src/events.rs @@ -28,6 +28,7 @@ pub(crate) const WM_GPUI_FORCE_UPDATE_WINDOW: u32 = WM_USER + 5; pub(crate) const WM_GPUI_KEYBOARD_LAYOUT_CHANGED: u32 = WM_USER + 6; pub(crate) const WM_GPUI_GPU_DEVICE_LOST: u32 = WM_USER + 7; pub(crate) const WM_GPUI_KEYDOWN: u32 = WM_USER + 8; +pub(crate) const WM_GPUI_END_SESSION: u32 = WM_USER + 9; const SIZE_MOVE_LOOP_TIMER_ID: usize = 1; @@ -108,6 +109,8 @@ impl WindowsWindowInner { WM_PAINT => self.handle_paint_msg(handle), WM_CLOSE => self.handle_close_msg(), WM_DESTROY => self.handle_destroy_msg(handle), + WM_QUERYENDSESSION => Some(1), + WM_ENDSESSION => self.handle_end_session_msg(wparam), WM_MOUSEMOVE => self.handle_mouse_move_msg(handle, lparam, wparam), WM_MOUSELEAVE | WM_NCMOUSELEAVE => self.handle_mouse_leave_msg(), WM_NCMOUSEMOVE => self.handle_nc_mouse_move_msg(handle, lparam), @@ -170,6 +173,20 @@ impl WindowsWindowInner { } } + fn handle_end_session_msg(&self, wparam: WPARAM) -> Option { + if wparam.0 != 0 { + unsafe { + SendMessageW( + self.platform_window_handle, + WM_GPUI_END_SESSION, + Some(WPARAM(self.validation_number)), + None, + ); + } + } + Some(0) + } + fn handle_move_msg(&self, handle: HWND, lparam: LPARAM) -> Option { let origin = logical_point( lparam.signed_loword() as f32, diff --git a/crates/gpui_windows/src/platform.rs b/crates/gpui_windows/src/platform.rs index 0c0f18a0ee0..a47f4bb539f 100644 --- a/crates/gpui_windows/src/platform.rs +++ b/crates/gpui_windows/src/platform.rs @@ -997,7 +997,8 @@ impl WindowsPlatformInner { | WM_GPUI_TASK_DISPATCHED_ON_MAIN_THREAD | WM_GPUI_DOCK_MENU_ACTION | WM_GPUI_KEYBOARD_LAYOUT_CHANGED - | WM_GPUI_GPU_DEVICE_LOST => self.handle_gpui_events(msg, wparam, lparam), + | WM_GPUI_GPU_DEVICE_LOST + | WM_GPUI_END_SESSION => self.handle_gpui_events(msg, wparam, lparam), WM_POWERBROADCAST => self.handle_power_broadcast(wparam), _ => None, }; @@ -1022,10 +1023,20 @@ impl WindowsPlatformInner { WM_GPUI_DOCK_MENU_ACTION => self.handle_dock_action_event(lparam.0 as _), WM_GPUI_KEYBOARD_LAYOUT_CHANGED => self.handle_keyboard_layout_change(), WM_GPUI_GPU_DEVICE_LOST => self.handle_device_lost(lparam), + WM_GPUI_END_SESSION => self.handle_end_session(), _ => unreachable!(), } } + fn handle_end_session(&self) -> Option { + let callback = self.state.callbacks.quit.take(); + if let Some(mut callback) = callback { + callback(); + } + unsafe { PostQuitMessage(0) }; + Some(0) + } + fn close_one_window(&self, target_window: HWND) -> bool { let Some(all_windows) = self.raw_window_handles.upgrade() else { log::error!("Failed to upgrade raw window handles");