1use crate::driver::Driver;
14use std::future::Future;
15use std::future::poll_fn;
16use std::io;
17#[cfg(target_os = "linux")]
18use std::os::fd::OwnedFd;
19use std::task::Context;
20use std::task::Poll;
21use std::task::ready;
22
23#[cfg(target_os = "macos")]
25pub mod macos {
26 pub use crate::sys::process::macos::NoProcessWait;
27 pub use crate::sys::process::macos::PollProcessWait;
28 pub use crate::sys::process::macos::ProcessWaitDriver;
29 pub use crate::sys::process::macos::ProcessWaitImpl;
30}
31
32pub struct PolledChild<C> {
37 wait: Option<crate::sys::process::WaitInner>,
38 #[cfg(target_os = "linux")]
40 _owned_pidfd: Option<OwnedFd>,
41 child: C,
42}
43
44impl<C> PolledChild<C> {
45 pub fn into_inner(self) -> C {
47 self.child
48 }
49
50 pub fn get(&self) -> &C {
52 &self.child
53 }
54
55 pub fn get_mut(&mut self) -> &mut C {
57 &mut self.child
58 }
59}
60
61fn poll_child_exit(
74 cx: &mut Context<'_>,
75 wait: &mut Option<crate::sys::process::WaitInner>,
76 reap: impl FnOnce() -> io::Result<std::process::ExitStatus>,
77) -> Poll<io::Result<std::process::ExitStatus>> {
78 if let Some(w) = wait {
79 ready!(w.poll_exit(cx))?;
80 }
81 Poll::Ready(reap())
82}
83
84impl PolledChild<std::process::Child> {
87 pub fn new(driver: &(impl ?Sized + Driver), child: std::process::Child) -> io::Result<Self> {
89 Self::new_inner(driver, child)
90 }
91
92 pub fn poll_wait(
94 &mut self,
95 cx: &mut Context<'_>,
96 ) -> Poll<io::Result<std::process::ExitStatus>> {
97 poll_child_exit(cx, &mut self.wait, || self.child.wait())
98 }
99
100 pub fn wait(
102 &mut self,
103 ) -> impl '_ + Unpin + Future<Output = io::Result<std::process::ExitStatus>> {
104 poll_fn(move |cx| self.poll_wait(cx))
105 }
106}
107
108#[cfg(unix)]
111impl PolledChild<pal::unix::process::Child> {
112 pub fn new(
114 driver: &(impl ?Sized + Driver),
115 child: pal::unix::process::Child,
116 ) -> io::Result<Self> {
117 Self::new_inner(driver, child)
118 }
119
120 pub fn poll_wait(
122 &mut self,
123 cx: &mut Context<'_>,
124 ) -> Poll<io::Result<std::process::ExitStatus>> {
125 poll_child_exit(cx, &mut self.wait, || self.child.wait())
126 }
127
128 pub fn wait(
130 &mut self,
131 ) -> impl '_ + Unpin + Future<Output = io::Result<std::process::ExitStatus>> {
132 poll_fn(move |cx| self.poll_wait(cx))
133 }
134}
135
136#[cfg(windows)]
147pub struct PolledProcess {
148 wait: Option<crate::sys::process::WaitInner>,
149 process: pal::windows::Process,
150}
151
152#[cfg(windows)]
153impl PolledProcess {
154 pub fn new(
158 driver: &(impl ?Sized + Driver),
159 process: pal::windows::Process,
160 ) -> io::Result<Self> {
161 use crate::sys::process::HandleProcessWait;
162 use std::os::windows::prelude::*;
163
164 let handle = process.as_handle().as_raw_handle();
165 let wait = driver.new_dyn_wait(handle)?;
166 Ok(Self {
167 wait: Some(HandleProcessWait::new(wait)),
168 process,
169 })
170 }
171
172 pub fn into_inner(self) -> pal::windows::Process {
174 self.process
175 }
176
177 pub fn get(&self) -> &pal::windows::Process {
179 &self.process
180 }
181
182 pub fn poll_wait(&mut self, cx: &mut Context<'_>) -> Poll<io::Result<u32>> {
184 if let Some(wait) = &mut self.wait {
185 ready!(wait.poll_exit(cx))?;
186 }
187 Poll::Ready(Ok(self.process.exit_code()))
188 }
189
190 pub fn wait(&mut self) -> impl '_ + Unpin + Future<Output = io::Result<u32>> {
192 poll_fn(move |cx| self.poll_wait(cx))
193 }
194}
195
196impl<C> PolledChild<C> {
197 #[cfg_attr(windows, expect(dead_code))]
198 fn exited(child: C) -> Self {
200 Self {
201 wait: None,
202 #[cfg(target_os = "linux")]
203 _owned_pidfd: None,
204 child,
205 }
206 }
207}
208
209#[cfg(target_os = "linux")]
211mod linux {
212 #![expect(unsafe_code)]
214
215 use super::*;
216 use crate::sys::process::linux::FdProcessWait;
217 use std::os::unix::prelude::*;
218
219 fn pidfd_open(pid: i32) -> io::Result<OwnedFd> {
221 let fd = unsafe { libc::syscall(libc::SYS_pidfd_open, pid, 0 as libc::c_int) };
224 if fd < 0 {
225 return Err(io::Error::last_os_error());
226 }
227 Ok(unsafe { OwnedFd::from_raw_fd(fd as RawFd) })
229 }
230
231 impl PolledChild<std::process::Child> {
232 pub(super) fn new_inner(
233 driver: &(impl ?Sized + Driver),
234 mut child: std::process::Child,
235 ) -> io::Result<Self> {
236 if child.try_wait()?.is_some() {
239 return Ok(Self::exited(child));
240 }
241 let pidfd = pidfd_open(child.id() as i32)?;
242 let fd_ready = driver.new_dyn_fd_ready(pidfd.as_fd().as_raw_fd())?;
243 Ok(Self {
244 wait: Some(FdProcessWait::new(fd_ready)),
245 _owned_pidfd: Some(pidfd),
246 child,
247 })
248 }
249 }
250
251 impl PolledChild<pal::unix::process::Child> {
252 pub(super) fn new_inner(
253 driver: &(impl ?Sized + Driver),
254 child: pal::unix::process::Child,
255 ) -> io::Result<Self> {
256 let fd_ready = driver.new_dyn_fd_ready(child.as_fd().as_raw_fd())?;
257 Ok(Self {
258 wait: Some(FdProcessWait::new(fd_ready)),
259 _owned_pidfd: None,
260 child,
261 })
262 }
263 }
264}
265
266#[cfg(target_os = "macos")]
268mod macos_impl {
269 use super::*;
270 use crate::sys::process::WaitInner;
271
272 impl PolledChild<std::process::Child> {
273 pub(super) fn new_inner(
274 driver: &(impl ?Sized + Driver),
275 mut child: std::process::Child,
276 ) -> io::Result<Self> {
277 if child.try_wait()?.is_some() {
280 return Ok(Self::exited(child));
281 }
282 let wait = driver.new_dyn_process_wait(child.id() as i32)?;
283 Ok(Self {
284 wait: Some(WaitInner::new(wait)),
285 child,
286 })
287 }
288 }
289
290 impl PolledChild<pal::unix::process::Child> {
291 pub(super) fn new_inner(
292 driver: &(impl ?Sized + Driver),
293 mut child: pal::unix::process::Child,
294 ) -> io::Result<Self> {
295 if child.try_wait()?.is_some() {
298 return Ok(Self::exited(child));
299 }
300 let wait = driver.new_dyn_process_wait(child.id())?;
301 Ok(Self {
302 wait: Some(WaitInner::new(wait)),
303 child,
304 })
305 }
306 }
307}
308
309#[cfg(windows)]
311mod windows {
312 use super::*;
313 use crate::sys::process::HandleProcessWait;
314 use std::os::windows::prelude::*;
315
316 impl PolledChild<std::process::Child> {
317 pub(super) fn new_inner(
318 driver: &(impl ?Sized + Driver),
319 child: std::process::Child,
320 ) -> io::Result<Self> {
321 let handle = child.as_handle().as_raw_handle();
322 let wait = driver.new_dyn_wait(handle)?;
323 Ok(Self {
324 wait: Some(HandleProcessWait::new(wait)),
325 child,
326 })
327 }
328 }
329}