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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
//! Executor-side SIGTERM catch (ARCH §2.9 step 3).
//!
//! When a stop is issued the whole harness process group is signalled —
//! `lernie stop` does `kill(-pgid, SIGTERM)` (`stop::cascade`), so the
//! provider adapter (`bz`) and every tool subprocess receive their *own*
//! SIGTERM delivery and die at once, `bz` installing no handler so its
//! `response.json` closes without a trailing `end` (the §2.9 stop
//! signature, §3.5). The executor catches its own copy of that same
//! group signal here: catching it shields nobody (the kernel already
//! delivered to each group member), it only lets the executor deposit its
//! branch's **result message** with a `stopped` epitaph on its way out
//! (§2.6, §2.3 step 5, "Return is not a verb") instead of dying on the
//! spot.
//!
//! **Async-signal-safety.** The handler does one thing — a single atomic
//! store (on POSIX's async-signal-safe list). The deposit runs *outside*
//! the handler, at the step loop's ordinary check points and once more on
//! the way out ([`super::run_exchange`]); §2.9's contract is "on its way
//! out", not "inside the handler". Mirrors the flag-and-poll shape the
//! `bash` built-in already uses (`tool::builtin::bash`) — a minimal
//! `libc::signal` registration, no new dependency.
use OnceLock;
use ;
/// Process-wide SIGTERM flag. Set by [`on_sigterm`]; read (through the
/// injected [`Deps::stop`]) at the [`super::run_exchange`] check points.
static SIGTERM_FLAG: AtomicBool = new;
/// Guards a single [`libc::signal`] registration per process.
static HANDLER_INSTALLED: = new;
/// The signal handler: a lone async-signal-safe atomic store. The step
/// loop observes it on its next check-point tick.
extern "C"
/// Install [`on_sigterm`] for `SIGTERM`, once per process (`lernie
/// prompt` at top-of-main, beside `stop::become_pgid_leader`). Idempotent
/// — a second call is a no-op.
/// The process-wide flag, for the production [`Deps::stop`] wiring in the
/// `lernie prompt` bin. Tests inject their own flag instead.
/// Whether a stop has been requested — the injected flag observed at a
/// check point (§2.9 step 3). Callers pass [`Deps::stop`](super::Deps),
/// so every check point is exercised deterministically with a
/// constructed flag, never the process-wide static, in tests.
pub