From 62f020312cc53210746c6f22bccda6b9a5be9a0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Soares?= <37777652+Dnreikronos@users.noreply.github.com> Date: Tue, 21 Apr 2026 04:56:21 -0300 Subject: [PATCH] terminal: Send SIGTERM synchronously on terminal drop (#53107) Self-Review Checklist: - [x] I've reviewed my own diff for quality, security, and reliability - [x] Unsafe blocks (if any) have justifying comments - [x] The content is consistent with the [UI/UX checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist) - [ ] Tests cover the new/changed behavior - [x] Performance impact has been considered and is acceptable Partially addresses #51455 Release Notes: - Fixed terminal child processes surviving after closing Zed by sending SIGTERM synchronously on terminal drop --- crates/terminal/src/pty_info.rs | 11 +++++++++++ crates/terminal/src/terminal.rs | 1 + 2 files changed, 12 insertions(+) diff --git a/crates/terminal/src/pty_info.rs b/crates/terminal/src/pty_info.rs index 7b6676760ca61c1cfde22601d0c0eb0b9641b42a..4e16d69e40553c359056934a4b49b2955a017ab5 100644 --- a/crates/terminal/src/pty_info.rs +++ b/crates/terminal/src/pty_info.rs @@ -157,6 +157,17 @@ impl PtyProcessInfo { self.get_child().is_some_and(|process| process.kill()) } + #[cfg(unix)] + pub(crate) fn terminate_child_process(&self) -> bool { + let pid = self.pid_getter.fallback_pid(); + unsafe { libc::killpg(pid.as_u32() as i32, libc::SIGTERM) == 0 } + } + + #[cfg(not(unix))] + pub(crate) fn terminate_child_process(&self) -> bool { + false + } + fn load(&self) -> Option { let process = self.refresh()?; let cwd = process.cwd().map_or(PathBuf::new(), |p| p.to_owned()); diff --git a/crates/terminal/src/terminal.rs b/crates/terminal/src/terminal.rs index b620f5f03c2debf19cdc4856da8c039fe690651f..74118d372d91cf99714dfeecb63e6b6b24e18c41 100644 --- a/crates/terminal/src/terminal.rs +++ b/crates/terminal/src/terminal.rs @@ -2424,6 +2424,7 @@ impl Drop for Terminal { std::mem::replace(&mut self.terminal_type, TerminalType::DisplayOnly) { pty_tx.0.send(Msg::Shutdown).ok(); + info.terminate_child_process(); let timer = self.background_executor.timer(Duration::from_millis(100)); self.background_executor