diff --git a/tokio/src/process/unix/mod.rs b/tokio/src/process/unix/mod.rs index e12869737eb..5a88ba8303c 100644 --- a/tokio/src/process/unix/mod.rs +++ b/tokio/src/process/unix/mod.rs @@ -103,15 +103,15 @@ impl OrphanQueue for GlobalOrphanQueue { } #[must_use = "futures do nothing unless polled"] -pub(crate) struct Child { - inner: Reaper, +pub(crate) enum Child { + SignalReaper(Reaper), + #[cfg(target_os = "linux")] + PidfdReaper(pidfd_reaper::PidfdReaper), } impl fmt::Debug for Child { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_struct("Child") - .field("pid", &self.inner.id()) - .finish() + fmt.debug_struct("Child").field("pid", &self.id()).finish() } } @@ -121,12 +121,24 @@ pub(crate) fn spawn_child(cmd: &mut std::process::Command) -> io::Result { + return Ok(SpawnedChild { + child: Child::PidfdReaper(pidfd_reaper), + stdin, + stdout, + stderr, + }) + } + Err((Some(err), _child)) => return Err(err), + Err((None, child_returned)) => child = child_returned, + } + let signal = signal(SignalKind::child())?; Ok(SpawnedChild { - child: Child { - inner: Reaper::new(child, GlobalOrphanQueue, signal), - }, + child: Child::SignalReaper(Reaper::new(child, GlobalOrphanQueue, signal)), stdin, stdout, stderr, @@ -135,25 +147,41 @@ pub(crate) fn spawn_child(cmd: &mut std::process::Command) -> io::Result u32 { - self.inner.id() + match self { + Self::SignalReaper(signal_reaper) => signal_reaper.id(), + #[cfg(target_os = "linux")] + Self::PidfdReaper(pidfd_reaper) => pidfd_reaper.id(), + } + } + + fn std_child(&mut self) -> &mut StdChild { + match self { + Self::SignalReaper(signal_reaper) => signal_reaper.inner_mut(), + #[cfg(target_os = "linux")] + Self::PidfdReaper(pidfd_reaper) => pidfd_reaper.inner_mut(), + } } pub(crate) fn try_wait(&mut self) -> io::Result> { - self.inner.inner_mut().try_wait() + self.std_child().try_wait() } } impl Kill for Child { fn kill(&mut self) -> io::Result<()> { - self.inner.kill() + self.std_child().kill() } } impl Future for Child { type Output = io::Result; - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - Pin::new(&mut self.inner).poll(cx) + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + match Pin::into_inner(self) { + Self::SignalReaper(signal_reaper) => Pin::new(signal_reaper).poll(cx), + #[cfg(target_os = "linux")] + Self::PidfdReaper(pidfd_reaper) => Pin::new(pidfd_reaper).poll(cx), + } } } diff --git a/tokio/src/process/unix/pidfd_reaper.rs b/tokio/src/process/unix/pidfd_reaper.rs index fd7a9c5a7d2..1aaf2352eec 100644 --- a/tokio/src/process/unix/pidfd_reaper.rs +++ b/tokio/src/process/unix/pidfd_reaper.rs @@ -112,14 +112,14 @@ impl PidfdReaper where W: Wait + Send + Sync + Unpin + 'static, { - pub(crate) fn new(inner: W) -> io::Result> { + pub(crate) fn new(inner: W) -> Result, W)> { if let Some(pidfd) = Pidfd::open(inner.id()) { - Ok(Some(Self(Some(PidfdReaperInner { - pidfd: PollEvented::new_with_interest(pidfd, Interest::READABLE)?, - inner, - })))) + match PollEvented::new_with_interest(pidfd, Interest::READABLE) { + Ok(pidfd) => Ok(Self(Some(PidfdReaperInner { pidfd, inner }))), + Err(io_error) => Err((Some(io_error), inner)), + } } else { - Ok(None) + Err((None, inner)) } }