1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
//! Signal-driven emergency teardown of detached child processes.
//!
//! dirge spawns its long-lived children — LSP servers (rust-analyzer &c.),
//! MCP servers, DAP adapters, bash subtrees — into their own sessions via
//! `setsid` ([`crate::child_guard::detach_session`]). That gives them no
//! controlling terminal, which protects the TUI but also means a signal the
//! terminal delivers (SIGHUP when the window/tab closes, SIGINT/SIGQUIT to
//! the foreground process group) never reaches them. The only thing that
//! reaps such a child is an explicit `kill(-pgid)`, and dirge issues that
//! from each guard's `Drop`.
//!
//! `Drop` runs on a normal return or an unwinding panic — but NOT when the
//! process is itself killed by a signal. So a plain `kill <pid>` (SIGTERM),
//! a closed terminal (SIGHUP), or a `kill -INT` left rust-analyzer orphaned,
//! still indexing the workspace and holding a gigabyte of RAM (dirge-6klk).
//!
//! This module installs an async task that awaits those signals, reaps every
//! registered child group via [`crate::child_guard::reap_all_groups`],
//! restores the terminal, and exits with the conventional `128 + signum`
//! status. It complements — does not replace — the per-guard `Drop`, which
//! still handles every normal exit and sends the graceful LSP shutdown.
/// Spawn the signal reaper. Call once, early in `main`, inside the tokio
/// runtime and before any child is spawned. No-op off Unix, where children
/// aren't `setsid`-detached and `kill_on_drop` is the whole story.