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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
//! The crate's confined `unsafe` — **four raw process effects**, all of them
//! things std gives no safe wrapper for and none of them reducible.
//! [`sigterm`] is the best-effort `SIGTERM` [`super::Stream`]'s drop sends
//! before escalating to `Child::kill` (SIGKILL); [`set_env`] is the process
//! environment mutation the nested world needs to become a *place* and not only
//! a value ([`crate::world::inhabit`], DESIGN §16.2, bl-81c9);
//! [`term_disposition`] is the `SIGTERM` *catch* an engine needs before either
//! of those can happen at all (§8.5, bl-269a) — under the default disposition
//! the process dies where it stands, so no `Drop` runs and the `sigterm` above
//! is never posted; and [`ignore_sigpipe`] is the disposition repair a RETURNED
//! `exec` owes this process ([`crate::git_env::exec`], bl-3792). Two of the
//! four are therefore signal dispositions, and they are opposites on purpose:
//! one asks to be told about a death, the other refuses one. The
//! `unsafe-outside-sys` ast-grep rule (`rules/unsafe-outside-sys.yml`) bans
//! `unsafe` everywhere else in the tree, so this file is the one audited home
//! for it — keeping the whole-crate `unsafe` inventory at exactly one site,
//! which is why the env fold lives here rather than beside its caller.
/// Post `SIGTERM` to `pid`. Best-effort: a failed `kill` (e.g. ESRCH — the
/// child already exited and was reaped) is intentionally discarded, since
/// [`super::Stream`]'s drop follows up with a hard `Child::kill` + `wait`
/// regardless.
pub
/// Set every `(var, value)` pair in **this process's** environment. The one env
/// mutation in the tree, and the only way the world can reach an in-process
/// substrate arm (§16.7): the linked `balls`/`litany` read `getenv` themselves
/// and spawn children that do the same, so there is no `Env` to inject — the
/// process has to stand in the world. Its production callers are the `world`
/// module's two place-folds and nothing else: [`crate::world::inhabit`] (the
/// §16.2 override set) and [`crate::world::inhabit_space`] (the §16.3 space,
/// layered on it one var deep — bl-c21d).
pub
/// Process-wide "a stop was asked for" flag. Set by [`on_term`] and read
/// through [`term_flag`]; the *only* thing a SIGTERM does to this process once
/// [`term_disposition`] has pointed the signal here.
static TERM_REQUESTED: AtomicBool = new;
/// The SIGTERM handler: one atomic store, which POSIX lists as
/// async-signal-safe. Everything a stop *means* (§8.5) happens outside it, in
/// the face's own loop — a handler that dropped the engine would run arbitrary
/// code, take locks and join threads on a signal stack.
///
/// `pub(crate)` so the §8.5 stop's one process-wide test drives it **as a
/// function** rather than by signalling the test binary: this suite runs under
/// tarpaulin's ptrace, whose signal bookkeeping is exactly what `tarpaulin.toml`
/// already pins the run serial to work around. What a delivered SIGTERM would
/// prove beyond this call is `signal(2)`'s own contract, not yog's.
pub extern "C"
/// Point `SIGTERM` at [`on_term`] (`catch`) or back at the kernel's default
/// terminate disposition (`!catch`). The third raw process effect, and the one
/// that makes the two above reachable at all: the default disposition kills the
/// process outright, so no `Drop` runs and [`super::Stream`]'s SIGTERM above is
/// never posted.
///
/// One function with a boolean rather than an install/restore pair, because
/// `signal(2)` is one call either way and is idempotent — the second install of
/// the same handler is a no-op, so there is nothing for a `OnceLock` to guard.
/// The restoring direction is what keeps the *test* that installs the real
/// handler hermetic: it hands the disposition back rather than leaving the rest
/// of a suite unable to die on a signal.
pub
/// The flag [`on_term`] sets — `pub(crate)` and a borrow on purpose: it is one
/// process-wide fact and every reader must read *that* one, never a copy.
pub
/// Set `SIGPIPE` to `SIG_IGN` — the disposition Rust's runtime installs before
/// `main`, and the one every safe write in this process is written against: it
/// is what makes a reader that went away a [`BrokenPipe`] error instead of a
/// death.
///
/// **It is a repair, not a policy.** Its one caller is
/// [`crate::git_env::exec`], on the only path that can reach it:
/// `CommandExt::exec` does not fork, so std's `do_exec` runs in *this* process
/// and resets `SIGPIPE` to `SIG_DFL` on its way to `execvp` — and an `execvp`
/// that fails hands back a live process with that reset standing (bl-3792).
///
/// [`BrokenPipe`]: std::io::ErrorKind::BrokenPipe
pub