66
77use 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 ;
11- #[ cfg( not( doc) ) ]
1211use crate :: sys:: fd:: FileDesc ;
12+ #[ cfg( not( doc) ) ]
13+ use crate :: sys:: linux:: pidfd:: PidFd as InnerPidFd ;
1314use crate :: sys_common:: { AsInner , AsInnerMut , FromInner , IntoInner } ;
1415
1516#[ cfg( doc) ]
16- struct FileDesc ;
17+ struct InnerPidFd ;
1718
1819/// This type represents a file descriptor that refers to a process.
1920///
2021/// A `PidFd` can be obtained by setting the corresponding option on [`Command`]
2122/// with [`create_pidfd`]. Subsequently, the created pidfd can be retrieved
22- /// from the [`Child`] by calling [`pidfd`] or [`take_pidfd `].
23+ /// from the [`Child`] by calling [`pidfd`] or [`into_pidfd `].
2324///
2425/// Example:
2526/// ```no_run
@@ -33,7 +34,7 @@ struct FileDesc;
3334/// .expect("Failed to spawn child");
3435///
3536/// let pidfd = child
36- /// .take_pidfd ()
37+ /// .into_pidfd ()
3738/// .expect("Failed to retrieve pidfd");
3839///
3940/// // The file descriptor will be closed when `pidfd` is dropped.
@@ -44,66 +45,101 @@ struct FileDesc;
4445/// [`create_pidfd`]: CommandExt::create_pidfd
4546/// [`Child`]: process::Child
4647/// [`pidfd`]: fn@ChildExt::pidfd
47- /// [`take_pidfd `]: ChildExt::take_pidfd
48+ /// [`into_pidfd `]: ChildExt::into_pidfd
4849/// [`pidfd_open(2)`]: https://man7.org/linux/man-pages/man2/pidfd_open.2.html
4950#[ derive( Debug ) ]
51+ #[ repr( transparent) ]
5052pub struct PidFd {
51- inner : FileDesc ,
53+ inner : InnerPidFd ,
54+ }
55+
56+ impl PidFd {
57+ /// Forces the child process to exit.
58+ ///
59+ /// Unlike [`Child::kill`] it is possible to attempt to kill
60+ /// reaped children since PidFd does not suffer from pid recycling
61+ /// races. But doing so will return an Error.
62+ ///
63+ /// [`Child::kill`]: process::Child::kill
64+ pub fn kill ( & self ) -> Result < ( ) > {
65+ self . inner . kill ( )
66+ }
67+
68+ /// Waits for the child to exit completely, returning the status that it exited with.
69+ ///
70+ /// Unlike [`Child::wait`] it does not ensure that the stdin handle is closed.
71+ /// Additionally it will not return an `ExitStatus` if the child
72+ /// has already been reaped. Instead an error will be returned.
73+ ///
74+ /// [`Child::wait`]: process::Child::wait
75+ pub fn wait ( & self ) -> Result < ExitStatus > {
76+ self . inner . wait ( ) . map ( FromInner :: from_inner)
77+ }
78+
79+ /// Attempts to collect the exit status of the child if it has already exited.
80+ ///
81+ /// Unlike [`Child::try_wait`] this method will return an Error
82+ /// if the child has already been reaped.
83+ ///
84+ /// [`Child::try_wait`]: process::Child::try_wait
85+ pub fn try_wait ( & self ) -> Result < Option < ExitStatus > > {
86+ Ok ( self . inner . try_wait ( ) ?. map ( FromInner :: from_inner) )
87+ }
5288}
5389
54- impl AsInner < FileDesc > for PidFd {
90+ impl AsInner < InnerPidFd > for PidFd {
5591 #[ inline]
56- fn as_inner ( & self ) -> & FileDesc {
92+ fn as_inner ( & self ) -> & InnerPidFd {
5793 & self . inner
5894 }
5995}
6096
61- impl FromInner < FileDesc > for PidFd {
62- fn from_inner ( inner : FileDesc ) -> PidFd {
97+ impl FromInner < InnerPidFd > for PidFd {
98+ fn from_inner ( inner : InnerPidFd ) -> PidFd {
6399 PidFd { inner }
64100 }
65101}
66102
67- impl IntoInner < FileDesc > for PidFd {
68- fn into_inner ( self ) -> FileDesc {
103+ impl IntoInner < InnerPidFd > for PidFd {
104+ fn into_inner ( self ) -> InnerPidFd {
69105 self . inner
70106 }
71107}
72108
73109impl AsRawFd for PidFd {
74110 #[ inline]
75111 fn as_raw_fd ( & self ) -> RawFd {
76- self . as_inner ( ) . as_raw_fd ( )
112+ self . as_inner ( ) . as_inner ( ) . as_raw_fd ( )
77113 }
78114}
79115
80116impl FromRawFd for PidFd {
81117 unsafe fn from_raw_fd ( fd : RawFd ) -> Self {
82- Self :: from_inner ( FileDesc :: from_raw_fd ( fd) )
118+ Self :: from_inner ( InnerPidFd :: from_raw_fd ( fd) )
83119 }
84120}
85121
86122impl IntoRawFd for PidFd {
87123 fn into_raw_fd ( self ) -> RawFd {
88- self . into_inner ( ) . into_raw_fd ( )
124+ self . into_inner ( ) . into_inner ( ) . into_raw_fd ( )
89125 }
90126}
91127
92128impl AsFd for PidFd {
93129 fn as_fd ( & self ) -> BorrowedFd < ' _ > {
94- self . as_inner ( ) . as_fd ( )
130+ self . as_inner ( ) . as_inner ( ) . as_fd ( )
95131 }
96132}
97133
98134impl From < OwnedFd > for PidFd {
99135 fn from ( fd : OwnedFd ) -> Self {
100- Self :: from_inner ( FileDesc :: from_inner ( fd) )
136+ Self :: from_inner ( InnerPidFd :: from_inner ( FileDesc :: from_inner ( fd) ) )
101137 }
102138}
103139
104140impl From < PidFd > for OwnedFd {
105141 fn from ( pid_fd : PidFd ) -> Self {
106- pid_fd. into_inner ( ) . into_inner ( )
142+ pid_fd. into_inner ( ) . into_inner ( ) . into_inner ( )
107143 }
108144}
109145
@@ -124,18 +160,26 @@ pub trait ChildExt: Sealed {
124160 /// [`Child`]: process::Child
125161 fn pidfd ( & self ) -> Result < & PidFd > ;
126162
127- /// Takes ownership of the [`PidFd`] created for this [`Child`], if available.
163+ /// Returns the [`PidFd`] created for this [`Child`], if available.
164+ /// Otherwise self is returned.
128165 ///
129166 /// A pidfd will only be available if its creation was requested with
130167 /// [`create_pidfd`] when the corresponding [`Command`] was created.
131168 ///
169+ /// Taking ownership of the PidFd consumes the Child to avoid pid reuse
170+ /// races. Use [`pidfd`] and [`BorrowedFd::try_clone_to_owned`] if
171+ /// you don't want to disassemble the Child yet.
172+ ///
132173 /// Even if requested, a pidfd may not be available due to an older
133174 /// version of Linux being in use, or if some other error occurred.
134175 ///
135176 /// [`Command`]: process::Command
136177 /// [`create_pidfd`]: CommandExt::create_pidfd
178+ /// [`pidfd`]: ChildExt::pidfd
137179 /// [`Child`]: process::Child
138- fn take_pidfd ( & mut self ) -> Result < PidFd > ;
180+ fn into_pidfd ( self ) -> crate :: result:: Result < PidFd , Self >
181+ where
182+ Self : Sized ;
139183}
140184
141185/// Os-specific extensions for [`Command`]
@@ -146,7 +190,7 @@ pub trait CommandExt: Sealed {
146190 /// spawned by this [`Command`].
147191 /// By default, no pidfd will be created.
148192 ///
149- /// The pidfd can be retrieved from the child with [`pidfd`] or [`take_pidfd `].
193+ /// The pidfd can be retrieved from the child with [`pidfd`] or [`into_pidfd `].
150194 ///
151195 /// A pidfd will only be created if it is possible to do so
152196 /// in a guaranteed race-free manner. Otherwise, [`pidfd`] will return an error.
@@ -160,7 +204,7 @@ pub trait CommandExt: Sealed {
160204 /// [`Command`]: process::Command
161205 /// [`Child`]: process::Child
162206 /// [`pidfd`]: fn@ChildExt::pidfd
163- /// [`take_pidfd `]: ChildExt::take_pidfd
207+ /// [`into_pidfd `]: ChildExt::into_pidfd
164208 fn create_pidfd ( & mut self , val : bool ) -> & mut process:: Command ;
165209}
166210
0 commit comments