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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
//! [`ShutdownReport`] — the observed facts of a graceful
//! [`ProcessGroup`](crate::ProcessGroup) teardown.
use Duration;
use crateSignal;
use crate;
/// The fate of a graceful teardown's best-effort **soft-signal** tier — what the
/// kernel actually observed of the polite "please exit" request
/// [`ProcessGroup::stop`](crate::ProcessGroup::stop) issues before the grace
/// window, as opposed to what it *tried* to do.
///
/// The soft signal is a `SIGTERM` (the graceful signal; [`Signal::Term`]) on the
/// Unix mechanisms, and a `CTRL_BREAK`/`WM_CLOSE` trigger on the Windows soft tier.
/// It is deliberately **not** the hard kill: escalation to `SIGKILL` /
/// `cgroup.kill` / `TerminateJobObject` is reported separately by
/// [`ShutdownReport::escalated`].
///
/// # No string format
///
/// This is an accessor/variant type, not a rendered string — match on it (or read
/// [`ShutdownReport::attempted_signal`]) rather than parsing a `Debug`/`Display`
/// form, which is not a stability contract.
/// The observed facts of one graceful group teardown, returned by
/// [`ProcessGroup::stop`](crate::ProcessGroup::stop).
///
/// Where the fire-and-forget [`shutdown`](crate::ProcessGroup::shutdown) /
/// [`shutdown_ref`](crate::ProcessGroup::shutdown_ref) report only success or an
/// error, this carries what the teardown **actually observed**: which soft signal
/// was attempted and whether it landed, how many members were alive before and
/// after, whether the tree drained within the grace or had to be hard-killed, and
/// how long it really took. A consumer that owns its own end-of-run race (its
/// deadline is not [`Command::timeout`](crate::Command::timeout) but a
/// timeout ⨯ Ctrl-C ⨯ control-socket race) can report the *observed* tier instead
/// of re-deriving it, and stop waiting the instant the tree is empty rather than
/// always spending the whole grace.
///
/// # Point-in-time member counts
///
/// [`members_before`](Self::members_before) / [`members_after`](Self::members_after)
/// count the same member set the group's
/// [`members`](crate::ProcessGroup::members) reports — the whole tree on the
/// Windows Job Object and Linux cgroup mechanisms, the tracked group **leaders** on
/// the POSIX process-group fallback (macOS/BSD and Linux without a usable cgroup).
/// Each is `None` only if that membership read failed (an unreadable `cgroup.procs`,
/// a failed Job Object query), never a fabricated `0`.
///
/// On the process-group fallback an **unreaped zombie still counts as a member**
/// (its process-group entry survives until the child is `wait`ed), so a tree
/// hard-killed with `SIGKILL` can still report a non-zero
/// [`members_after`](Self::members_after) until those exits are reaped — the same
/// reaping caveat [`shutdown`](crate::ProcessGroup::shutdown) documents. The atomic
/// mechanisms (`cgroup.procs`, the Job Object) drop a process on exit, before
/// reaping.
///
/// # Non-exhaustive, accessor-only
///
/// A read-only snapshot the crate produces: non-exhaustive so new facts can be
/// added without a breaking change, and each fact is exposed through a method
/// (documenting its own platform caveats) rather than a public field. There is
/// **no** string format to parse as a contract.