about summary refs log tree commit diff
path: root/library/std/src/os/linux/process.rs
diff options
context:
space:
mode:
Diffstat (limited to 'library/std/src/os/linux/process.rs')
-rw-r--r--library/std/src/os/linux/process.rs89
1 files changed, 66 insertions, 23 deletions
diff --git a/library/std/src/os/linux/process.rs b/library/std/src/os/linux/process.rs
index 2ba67a6dd1a..91959094797 100644
--- a/library/std/src/os/linux/process.rs
+++ b/library/std/src/os/linux/process.rs
@@ -6,20 +6,20 @@
 
 use crate::io::Result;
 use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
-use crate::process;
+use crate::process::{self, ExitStatus};
 use crate::sealed::Sealed;
 #[cfg(not(doc))]
-use crate::sys::fd::FileDesc;
+use crate::sys::{fd::FileDesc, linux::pidfd::PidFd as InnerPidFd};
 use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
 
 #[cfg(doc)]
-struct FileDesc;
+struct InnerPidFd;
 
 /// This type represents a file descriptor that refers to a process.
 ///
 /// A `PidFd` can be obtained by setting the corresponding option on [`Command`]
 /// with [`create_pidfd`]. Subsequently, the created pidfd can be retrieved
-/// from the [`Child`] by calling [`pidfd`] or [`take_pidfd`].
+/// from the [`Child`] by calling [`pidfd`] or [`into_pidfd`].
 ///
 /// Example:
 /// ```no_run
@@ -33,7 +33,7 @@ struct FileDesc;
 ///     .expect("Failed to spawn child");
 ///
 /// let pidfd = child
-///     .take_pidfd()
+///     .into_pidfd()
 ///     .expect("Failed to retrieve pidfd");
 ///
 /// // The file descriptor will be closed when `pidfd` is dropped.
@@ -44,28 +44,63 @@ struct FileDesc;
 /// [`create_pidfd`]: CommandExt::create_pidfd
 /// [`Child`]: process::Child
 /// [`pidfd`]: fn@ChildExt::pidfd
-/// [`take_pidfd`]: ChildExt::take_pidfd
+/// [`into_pidfd`]: ChildExt::into_pidfd
 /// [`pidfd_open(2)`]: https://man7.org/linux/man-pages/man2/pidfd_open.2.html
 #[derive(Debug)]
+#[repr(transparent)]
 pub struct PidFd {
-    inner: FileDesc,
+    inner: InnerPidFd,
 }
 
-impl AsInner<FileDesc> for PidFd {
+impl PidFd {
+    /// Forces the child process to exit.
+    ///
+    /// Unlike [`Child::kill`] it is possible to attempt to kill
+    /// reaped children since PidFd does not suffer from pid recycling
+    /// races. But doing so will return an Error.
+    ///
+    /// [`Child::kill`]: process::Child::kill
+    pub fn kill(&self) -> Result<()> {
+        self.inner.kill()
+    }
+
+    /// Waits for the child to exit completely, returning the status that it exited with.
+    ///
+    /// Unlike [`Child::wait`] it does not ensure that the stdin handle is closed.
+    /// Additionally it will not return an `ExitStatus` if the child
+    /// has already been reaped. Instead an error will be returned.
+    ///
+    /// [`Child::wait`]: process::Child::wait
+    pub fn wait(&self) -> Result<ExitStatus> {
+        self.inner.wait().map(FromInner::from_inner)
+    }
+
+    /// Attempts to collect the exit status of the child if it has already exited.
+    ///
+    /// Unlike [`Child::try_wait`] this method will return an Error
+    /// if the child has already been reaped.
+    ///
+    /// [`Child::try_wait`]: process::Child::try_wait
+    pub fn try_wait(&self) -> Result<Option<ExitStatus>> {
+        Ok(self.inner.try_wait()?.map(FromInner::from_inner))
+    }
+}
+
+impl AsInner<InnerPidFd> for PidFd {
     #[inline]
-    fn as_inner(&self) -> &FileDesc {
+    fn as_inner(&self) -> &InnerPidFd {
         &self.inner
     }
 }
 
-impl FromInner<FileDesc> for PidFd {
-    fn from_inner(inner: FileDesc) -> PidFd {
+impl FromInner<InnerPidFd> for PidFd {
+    fn from_inner(inner: InnerPidFd) -> PidFd {
         PidFd { inner }
     }
 }
 
-impl IntoInner<FileDesc> for PidFd {
-    fn into_inner(self) -> FileDesc {
+impl IntoInner<InnerPidFd> for PidFd {
+    fn into_inner(self) -> InnerPidFd {
         self.inner
     }
 }
@@ -73,37 +108,37 @@ impl IntoInner<FileDesc> for PidFd {
 impl AsRawFd for PidFd {
     #[inline]
     fn as_raw_fd(&self) -> RawFd {
-        self.as_inner().as_raw_fd()
+        self.as_inner().as_inner().as_raw_fd()
     }
 }
 
 impl FromRawFd for PidFd {
     unsafe fn from_raw_fd(fd: RawFd) -> Self {
-        Self::from_inner(FileDesc::from_raw_fd(fd))
+        Self::from_inner(InnerPidFd::from_raw_fd(fd))
     }
 }
 
 impl IntoRawFd for PidFd {
     fn into_raw_fd(self) -> RawFd {
-        self.into_inner().into_raw_fd()
+        self.into_inner().into_inner().into_raw_fd()
     }
 }
 
 impl AsFd for PidFd {
     fn as_fd(&self) -> BorrowedFd<'_> {
-        self.as_inner().as_fd()
+        self.as_inner().as_inner().as_fd()
     }
 }
 
 impl From<OwnedFd> for PidFd {
     fn from(fd: OwnedFd) -> Self {
-        Self::from_inner(FileDesc::from_inner(fd))
+        Self::from_inner(InnerPidFd::from_inner(FileDesc::from_inner(fd)))
     }
 }
 
 impl From<PidFd> for OwnedFd {
     fn from(pid_fd: PidFd) -> Self {
-        pid_fd.into_inner().into_inner()
+        pid_fd.into_inner().into_inner().into_inner()
     }
 }
 
@@ -124,18 +159,26 @@ pub trait ChildExt: Sealed {
     /// [`Child`]: process::Child
     fn pidfd(&self) -> Result<&PidFd>;
 
-    /// Takes ownership of the [`PidFd`] created for this [`Child`], if available.
+    /// Returns the [`PidFd`] created for this [`Child`], if available.
+    /// Otherwise self is returned.
     ///
     /// A pidfd will only be available if its creation was requested with
     /// [`create_pidfd`] when the corresponding [`Command`] was created.
     ///
+    /// Taking ownership of the PidFd consumes the Child to avoid pid reuse
+    /// races. Use [`pidfd`] and [`BorrowedFd::try_clone_to_owned`] if
+    /// you don't want to disassemble the Child yet.
+    ///
     /// Even if requested, a pidfd may not be available due to an older
     /// version of Linux being in use, or if some other error occurred.
     ///
     /// [`Command`]: process::Command
     /// [`create_pidfd`]: CommandExt::create_pidfd
+    /// [`pidfd`]: ChildExt::pidfd
     /// [`Child`]: process::Child
-    fn take_pidfd(&mut self) -> Result<PidFd>;
+    fn into_pidfd(self) -> crate::result::Result<PidFd, Self>
+    where
+        Self: Sized;
 }
 
 /// Os-specific extensions for [`Command`]
@@ -146,7 +189,7 @@ pub trait CommandExt: Sealed {
     /// spawned by this [`Command`].
     /// By default, no pidfd will be created.
     ///
-    /// The pidfd can be retrieved from the child with [`pidfd`] or [`take_pidfd`].
+    /// The pidfd can be retrieved from the child with [`pidfd`] or [`into_pidfd`].
     ///
     /// A pidfd will only be created if it is possible to do so
     /// in a guaranteed race-free manner. Otherwise, [`pidfd`] will return an error.
@@ -160,7 +203,7 @@ pub trait CommandExt: Sealed {
     /// [`Command`]: process::Command
     /// [`Child`]: process::Child
     /// [`pidfd`]: fn@ChildExt::pidfd
-    /// [`take_pidfd`]: ChildExt::take_pidfd
+    /// [`into_pidfd`]: ChildExt::into_pidfd
     fn create_pidfd(&mut self, val: bool) -> &mut process::Command;
 }