Support Restart Manager shutdown on Windows

This commit is contained in:
John Tur 2026-08-21 01:06:46 -04:00
parent d9ad6aff67
commit 2cddfdbf20
3 changed files with 78 additions and 1 deletions

View file

@ -182,6 +182,7 @@ pub struct CrashServer {
active_gpu: Mutex<Option<system_specs::GpuSpecs>>,
user_info: Mutex<Option<UserInfo>>,
abort_message_location: Mutex<Option<AbortMessageLocation>>,
shutdown: Arc<AtomicBool>,
has_connection: Arc<AtomicBool>,
logs_dir: PathBuf,
}
@ -255,6 +256,11 @@ pub fn set_user_info(crash_client: &Arc<Client>, 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<Client>) {
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);

View file

@ -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<isize> {
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<isize> {
let origin = logical_point(
lparam.signed_loword() as f32,

View file

@ -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<isize> {
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");