diff --git a/crates/ide-host/src/lib.rs b/crates/ide-host/src/lib.rs index c1c76fdb..2dad9a5a 100644 --- a/crates/ide-host/src/lib.rs +++ b/crates/ide-host/src/lib.rs @@ -349,6 +349,14 @@ impl Host { } } + /// Called on desktop exit: kills the runs and terminal shells still alive. Closing a + /// window stops what it started, but a quit from the Dock, the app menu or a logout + /// exits without closing the windows, and the process trees would outlive the app. + pub fn stop_processes_on_exit(&self) { + self.processes.kill_all(); + self.terminals.kill_all(); + } + /// Called before desktop exit, which may bypass document destructors. pub fn clear_workspace_edit_history_on_exit(&self) { for project in self.projects() { diff --git a/crates/ide-run/tests/process.rs b/crates/ide-run/tests/process.rs index cbb2ba91..21524e4f 100644 --- a/crates/ide-run/tests/process.rs +++ b/crates/ide-run/tests/process.rs @@ -529,6 +529,30 @@ fn revoking_one_project_stops_only_its_runs() { h.pm.stop(theirs.id).unwrap(); } +/// Quitting the app kills what every project's runs started, forked children included (#1691). +#[test] +fn kill_all_stops_every_projects_process_trees() { + let h = harness(); + let other = tempfile::tempdir().unwrap(); + let (mine, chunks) = start(&h, &cfg("mine", "/bin/sh", &["-c", "sleep 30 & echo $!; wait"])); + let grandchild: i32 = wait_for(&chunks, "\n").trim().parse().expect("pid"); + let theirs = + h.pm.start( + other.path(), + &cfg("theirs", "/bin/sh", &["-c", "sleep 30"]), + &StartOptions::default(), + h.sink.clone(), + Box::new(|_| {}), + ) + .unwrap(); + h.pm.kill_all(); + let deadline = Instant::now() + Duration::from_secs(8); + while alive(grandchild) || h.pm.list().iter().any(|r| (r.id == mine || r.id == theirs.id) && r.running) { + assert!(Instant::now() < deadline, "a run survived kill_all"); + std::thread::sleep(Duration::from_millis(50)); + } +} + #[test] #[ignore = "requires CMake, CTest and a C++ compiler"] fn cmake_configure_discovers_builds_and_runs_a_multifile_target() { diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 86dc6dc2..9e02a874 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -234,6 +234,7 @@ pub fn run() { let _ = &early_opens; if let tauri::RunEvent::Exit = event { if let Some(state) = app.try_state::() { + state.host.stop_processes_on_exit(); state.host.clear_workspace_edit_history_on_exit(); state.host.shutdown_notebooks_on_exit(); }