Auto merge of #124101 - the8472:pidfd-methods, r=cuviper · rust-lang/rust@10e1f5d
@@ -6,20 +6,20 @@
6677use crate::io::Result;
88use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
9-use crate::process;
9+use crate::process::{self, ExitStatus};
1010use crate::sealed::Sealed;
1111#[cfg(not(doc))]
12-use crate::sys::fd::FileDesc;
12+use crate::sys::{fd::FileDesc, linux::pidfd::PidFd as InnerPidFd};
1313use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
14141515#[cfg(doc)]
16-struct FileDesc;
16+struct InnerPidFd;
17171818/// This type represents a file descriptor that refers to a process.
1919///
2020/// A `PidFd` can be obtained by setting the corresponding option on [`Command`]
2121/// with [`create_pidfd`]. Subsequently, the created pidfd can be retrieved
22-/// from the [`Child`] by calling [`pidfd`] or [`take_pidfd`].
22+/// from the [`Child`] by calling [`pidfd`] or [`into_pidfd`].
2323///
2424/// Example:
2525/// ```no_run
@@ -33,7 +33,7 @@ struct FileDesc;
3333/// .expect("Failed to spawn child");
3434///
3535/// let pidfd = child
36-/// .take_pidfd()
36+/// .into_pidfd()
3737/// .expect("Failed to retrieve pidfd");
3838///
3939/// // The file descriptor will be closed when `pidfd` is dropped.
@@ -44,66 +44,101 @@ struct FileDesc;
4444/// [`create_pidfd`]: CommandExt::create_pidfd
4545/// [`Child`]: process::Child
4646/// [`pidfd`]: fn@ChildExt::pidfd
47-/// [`take_pidfd`]: ChildExt::take_pidfd
47+/// [`into_pidfd`]: ChildExt::into_pidfd
4848/// [`pidfd_open(2)`]: https://man7.org/linux/man-pages/man2/pidfd_open.2.html
4949#[derive(Debug)]
50+#[repr(transparent)]
5051pub struct PidFd {
51-inner: FileDesc,
52+inner: InnerPidFd,
5253}
535454-impl AsInner<FileDesc> for PidFd {
55+impl PidFd {
56+/// Forces the child process to exit.
57+ ///
58+ /// Unlike [`Child::kill`] it is possible to attempt to kill
59+ /// reaped children since PidFd does not suffer from pid recycling
60+ /// races. But doing so will return an Error.
61+ ///
62+ /// [`Child::kill`]: process::Child::kill
63+ pub fn kill(&self) -> Result<()> {
64+self.inner.kill()
65+}
66+67+/// Waits for the child to exit completely, returning the status that it exited with.
68+ ///
69+ /// Unlike [`Child::wait`] it does not ensure that the stdin handle is closed.
70+ /// Additionally it will not return an `ExitStatus` if the child
71+ /// has already been reaped. Instead an error will be returned.
72+ ///
73+ /// [`Child::wait`]: process::Child::wait
74+ pub fn wait(&self) -> Result<ExitStatus> {
75+self.inner.wait().map(FromInner::from_inner)
76+}
77+78+/// Attempts to collect the exit status of the child if it has already exited.
79+ ///
80+ /// Unlike [`Child::try_wait`] this method will return an Error
81+ /// if the child has already been reaped.
82+ ///
83+ /// [`Child::try_wait`]: process::Child::try_wait
84+ pub fn try_wait(&self) -> Result<Option<ExitStatus>> {
85+Ok(self.inner.try_wait()?.map(FromInner::from_inner))
86+}
87+}
88+89+impl AsInner<InnerPidFd> for PidFd {
5590#[inline]
56-fn as_inner(&self) -> &FileDesc {
91+fn as_inner(&self) -> &InnerPidFd {
5792&self.inner
5893}
5994}
609561-impl FromInner<FileDesc> for PidFd {
62-fn from_inner(inner: FileDesc) -> PidFd {
96+impl FromInner<InnerPidFd> for PidFd {
97+fn from_inner(inner: InnerPidFd) -> PidFd {
6398PidFd { inner }
6499}
65100}
6610167-impl IntoInner<FileDesc> for PidFd {
68-fn into_inner(self) -> FileDesc {
102+impl IntoInner<InnerPidFd> for PidFd {
103+fn into_inner(self) -> InnerPidFd {
69104self.inner
70105}
71106}
7210773108impl AsRawFd for PidFd {
74109#[inline]
75110fn as_raw_fd(&self) -> RawFd {
76-self.as_inner().as_raw_fd()
111+self.as_inner().as_inner().as_raw_fd()
77112}
78113}
7911480115impl FromRawFd for PidFd {
81116unsafe fn from_raw_fd(fd: RawFd) -> Self {
82-Self::from_inner(FileDesc::from_raw_fd(fd))
117+Self::from_inner(InnerPidFd::from_raw_fd(fd))
83118}
84119}
8512086121impl IntoRawFd for PidFd {
87122fn into_raw_fd(self) -> RawFd {
88-self.into_inner().into_raw_fd()
123+self.into_inner().into_inner().into_raw_fd()
89124}
90125}
9112692127impl AsFd for PidFd {
93128fn as_fd(&self) -> BorrowedFd<'_> {
94-self.as_inner().as_fd()
129+self.as_inner().as_inner().as_fd()
95130}
96131}
9713298133impl From<OwnedFd> for PidFd {
99134fn from(fd: OwnedFd) -> Self {
100-Self::from_inner(FileDesc::from_inner(fd))
135+Self::from_inner(InnerPidFd::from_inner(FileDesc::from_inner(fd)))
101136}
102137}
103138104139impl From<PidFd> for OwnedFd {
105140fn from(pid_fd: PidFd) -> Self {
106- pid_fd.into_inner().into_inner()
141+ pid_fd.into_inner().into_inner().into_inner()
107142}
108143}
109144@@ -124,18 +159,26 @@ pub trait ChildExt: Sealed {
124159 /// [`Child`]: process::Child
125160 fn pidfd(&self) -> Result<&PidFd>;
126161127-/// Takes ownership of the [`PidFd`] created for this [`Child`], if available.
162+/// Returns the [`PidFd`] created for this [`Child`], if available.
163+ /// Otherwise self is returned.
128164 ///
129165 /// A pidfd will only be available if its creation was requested with
130166 /// [`create_pidfd`] when the corresponding [`Command`] was created.
131167 ///
168+ /// Taking ownership of the PidFd consumes the Child to avoid pid reuse
169+ /// races. Use [`pidfd`] and [`BorrowedFd::try_clone_to_owned`] if
170+ /// you don't want to disassemble the Child yet.
171+ ///
132172 /// Even if requested, a pidfd may not be available due to an older
133173 /// version of Linux being in use, or if some other error occurred.
134174 ///
135175 /// [`Command`]: process::Command
136176 /// [`create_pidfd`]: CommandExt::create_pidfd
177+ /// [`pidfd`]: ChildExt::pidfd
137178 /// [`Child`]: process::Child
138- fn take_pidfd(&mut self) -> Result<PidFd>;
179+ fn into_pidfd(self) -> crate::result::Result<PidFd, Self>
180+where
181+Self: Sized;
139182}
140183141184/// Os-specific extensions for [`Command`]
@@ -146,7 +189,7 @@ pub trait CommandExt: Sealed {
146189 /// spawned by this [`Command`].
147190 /// By default, no pidfd will be created.
148191 ///
149- /// The pidfd can be retrieved from the child with [`pidfd`] or [`take_pidfd`].
192+ /// The pidfd can be retrieved from the child with [`pidfd`] or [`into_pidfd`].
150193 ///
151194 /// A pidfd will only be created if it is possible to do so
152195 /// in a guaranteed race-free manner. Otherwise, [`pidfd`] will return an error.
@@ -160,7 +203,7 @@ pub trait CommandExt: Sealed {
160203 /// [`Command`]: process::Command
161204 /// [`Child`]: process::Child
162205 /// [`pidfd`]: fn@ChildExt::pidfd
163- /// [`take_pidfd`]: ChildExt::take_pidfd
206+ /// [`into_pidfd`]: ChildExt::into_pidfd
164207 fn create_pidfd(&mut self, val: bool) -> &mut process::Command;
165208}
166209