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 ;
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 } ;
1414
1515#[ cfg( doc) ]
16- struct FileDesc ;
16+ struct InnerPidFd ;
1717
1818/// 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}
5354
54- 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}
6095
61- 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 {
6398 PidFd { inner }
6499 }
65100}
66101
67- impl IntoInner < FileDesc > for PidFd {
68- fn into_inner ( self ) -> FileDesc {
102+ impl IntoInner < InnerPidFd > for PidFd {
103+ fn into_inner ( self ) -> InnerPidFd {
69104 self . inner
70105 }
71106}
72107
73108impl AsRawFd for PidFd {
74109 #[ inline]
75110 fn as_raw_fd ( & self ) -> RawFd {
76- self . as_inner ( ) . as_raw_fd ( )
111+ self . as_inner ( ) . as_inner ( ) . as_raw_fd ( )
77112 }
78113}
79114
80115impl FromRawFd for PidFd {
81116 unsafe 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}
85120
86121impl IntoRawFd for PidFd {
87122 fn into_raw_fd ( self ) -> RawFd {
88- self . into_inner ( ) . into_raw_fd ( )
123+ self . into_inner ( ) . into_inner ( ) . into_raw_fd ( )
89124 }
90125}
91126
92127impl AsFd for PidFd {
93128 fn as_fd ( & self ) -> BorrowedFd < ' _ > {
94- self . as_inner ( ) . as_fd ( )
129+ self . as_inner ( ) . as_inner ( ) . as_fd ( )
95130 }
96131}
97132
98133impl From < OwnedFd > for PidFd {
99134 fn 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}
103138
104139impl From < PidFd > for OwnedFd {
105140 fn 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 > ;
126161
127- /// 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}
140183
141184/// 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
0 commit comments