async_process/reaper/
mod.rs
1#![allow(irrefutable_let_patterns)]
13
14#[cfg(any(windows, target_os = "linux"))]
16macro_rules! cfg_wait {
17 ($($tt:tt)*) => {$($tt)*};
18}
19
20#[cfg(not(any(windows, target_os = "linux")))]
22macro_rules! cfg_wait {
23 ($($tt:tt)*) => {};
24}
25
26#[cfg(not(windows))]
28macro_rules! cfg_signal {
29 ($($tt:tt)*) => {$($tt)*};
30}
31
32#[cfg(windows)]
34macro_rules! cfg_signal {
35 ($($tt:tt)*) => {};
36}
37
38cfg_wait! {
39 mod wait;
40}
41
42cfg_signal! {
43 mod signal;
44}
45
46use std::io;
47use std::sync::Mutex;
48
49pub(crate) enum Reaper {
51 #[cfg(any(windows, target_os = "linux"))]
52 Wait(wait::Reaper),
54
55 #[cfg(not(windows))]
57 Signal(signal::Reaper),
58}
59
60pub(crate) enum ChildGuard {
62 #[cfg(any(windows, target_os = "linux"))]
63 Wait(wait::ChildGuard),
65
66 #[cfg(not(windows))]
68 Signal(signal::ChildGuard),
69}
70
71pub(crate) enum Lock {
73 #[cfg(any(windows, target_os = "linux"))]
74 Wait,
76
77 #[cfg(not(windows))]
79 Signal(signal::Lock),
80}
81
82impl Reaper {
83 pub(crate) fn new() -> Self {
85 cfg_wait! {
86 if wait::available() && !cfg!(async_process_force_signal_backend) {
87 return Self::Wait(wait::Reaper::new());
88 }
89 }
90
91 cfg_signal! {
93 return Self::Signal(signal::Reaper::new());
94 }
95
96 #[allow(unreachable_code)]
97 {
98 panic!("neither the signal backend nor the waiter backend is available")
99 }
100 }
101
102 pub(crate) async fn lock(&'static self) -> Lock {
106 cfg_wait! {
107 if let Self::Wait(_this) = self {
108 return Lock::Wait;
110 }
111 }
112
113 cfg_signal! {
114 if let Self::Signal(this) = self {
115 return Lock::Signal(this.lock().await);
117 }
118 }
119
120 unreachable!()
121 }
122
123 pub(crate) async fn reap(&'static self, lock: Lock) -> ! {
125 cfg_wait! {
126 if let (Self::Wait(this), Lock::Wait) = (self, &lock) {
127 this.reap().await;
128 }
129 }
130
131 cfg_signal! {
132 if let (Self::Signal(this), Lock::Signal(lock)) = (self, lock) {
133 this.reap(lock).await;
134 }
135 }
136
137 unreachable!()
138 }
139
140 pub(crate) fn register(&'static self, child: std::process::Child) -> io::Result<ChildGuard> {
142 cfg_wait! {
143 if let Self::Wait(this) = self {
144 return this.register(child).map(ChildGuard::Wait);
145 }
146 }
147
148 cfg_signal! {
149 if let Self::Signal(this) = self {
150 return this.register(child).map(ChildGuard::Signal);
151 }
152 }
153
154 unreachable!()
155 }
156
157 pub(crate) async fn status(
159 &'static self,
160 child: &Mutex<crate::ChildGuard>,
161 ) -> io::Result<std::process::ExitStatus> {
162 cfg_wait! {
163 if let Self::Wait(this) = self {
164 return this.status(child).await;
165 }
166 }
167
168 cfg_signal! {
169 if let Self::Signal(this) = self {
170 return this.status(child).await;
171 }
172 }
173
174 unreachable!()
175 }
176
177 pub(crate) fn has_zombies(&'static self) -> bool {
179 cfg_wait! {
180 if let Self::Wait(this) = self {
181 return this.has_zombies();
182 }
183 }
184
185 cfg_signal! {
186 if let Self::Signal(this) = self {
187 return this.has_zombies();
188 }
189 }
190
191 unreachable!()
192 }
193}
194
195impl ChildGuard {
196 pub(crate) fn get_mut(&mut self) -> &mut std::process::Child {
198 cfg_wait! {
199 if let Self::Wait(this) = self {
200 return this.get_mut();
201 }
202 }
203
204 cfg_signal! {
205 if let Self::Signal(this) = self {
206 return this.get_mut();
207 }
208 }
209
210 unreachable!()
211 }
212
213 pub(crate) fn reap(&mut self, reaper: &'static Reaper) {
215 cfg_wait! {
216 if let (Self::Wait(this), Reaper::Wait(reaper)) = (&mut *self, reaper) {
217 this.reap(reaper);
218 return;
219 }
220 }
221
222 cfg_signal! {
223 if let (Self::Signal(this), Reaper::Signal(reaper)) = (self, reaper) {
224 this.reap(reaper);
225 return;
226 }
227 }
228
229 unreachable!()
230 }
231}