6
6
7
7
use crate :: io:: Result ;
8
8
use crate :: os:: unix:: io:: { AsFd , AsRawFd , BorrowedFd , FromRawFd , IntoRawFd , OwnedFd , RawFd } ;
9
- use crate :: process;
9
+ use crate :: process:: { self , ExitStatus } ;
10
10
use crate :: sealed:: Sealed ;
11
11
#[ cfg( not( doc) ) ]
12
- use crate :: sys:: fd:: FileDesc ;
12
+ use crate :: sys:: { fd:: FileDesc , linux :: pidfd :: PidFd as InnerPidFd } ;
13
13
use crate :: sys_common:: { AsInner , AsInnerMut , FromInner , IntoInner } ;
14
14
15
15
#[ cfg( doc) ]
16
- struct FileDesc ;
16
+ struct InnerPidFd ;
17
17
18
18
/// This type represents a file descriptor that refers to a process.
19
19
///
20
20
/// A `PidFd` can be obtained by setting the corresponding option on [`Command`]
21
21
/// 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 `].
23
23
///
24
24
/// Example:
25
25
/// ```no_run
@@ -33,7 +33,7 @@ struct FileDesc;
33
33
/// .expect("Failed to spawn child");
34
34
///
35
35
/// let pidfd = child
36
- /// .take_pidfd ()
36
+ /// .into_pidfd ()
37
37
/// .expect("Failed to retrieve pidfd");
38
38
///
39
39
/// // The file descriptor will be closed when `pidfd` is dropped.
@@ -44,66 +44,101 @@ struct FileDesc;
44
44
/// [`create_pidfd`]: CommandExt::create_pidfd
45
45
/// [`Child`]: process::Child
46
46
/// [`pidfd`]: fn@ChildExt::pidfd
47
- /// [`take_pidfd `]: ChildExt::take_pidfd
47
+ /// [`into_pidfd `]: ChildExt::into_pidfd
48
48
/// [`pidfd_open(2)`]: https://man7.org/linux/man-pages/man2/pidfd_open.2.html
49
49
#[ derive( Debug ) ]
50
+ #[ repr( transparent) ]
50
51
pub struct PidFd {
51
- inner : FileDesc ,
52
+ inner : InnerPidFd ,
52
53
}
53
54
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 {
55
90
#[ inline]
56
- fn as_inner ( & self ) -> & FileDesc {
91
+ fn as_inner ( & self ) -> & InnerPidFd {
57
92
& self . inner
58
93
}
59
94
}
60
95
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 {
63
98
PidFd { inner }
64
99
}
65
100
}
66
101
67
- impl IntoInner < FileDesc > for PidFd {
68
- fn into_inner ( self ) -> FileDesc {
102
+ impl IntoInner < InnerPidFd > for PidFd {
103
+ fn into_inner ( self ) -> InnerPidFd {
69
104
self . inner
70
105
}
71
106
}
72
107
73
108
impl AsRawFd for PidFd {
74
109
#[ inline]
75
110
fn as_raw_fd ( & self ) -> RawFd {
76
- self . as_inner ( ) . as_raw_fd ( )
111
+ self . as_inner ( ) . as_inner ( ) . as_raw_fd ( )
77
112
}
78
113
}
79
114
80
115
impl FromRawFd for PidFd {
81
116
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) )
83
118
}
84
119
}
85
120
86
121
impl IntoRawFd for PidFd {
87
122
fn into_raw_fd ( self ) -> RawFd {
88
- self . into_inner ( ) . into_raw_fd ( )
123
+ self . into_inner ( ) . into_inner ( ) . into_raw_fd ( )
89
124
}
90
125
}
91
126
92
127
impl AsFd for PidFd {
93
128
fn as_fd ( & self ) -> BorrowedFd < ' _ > {
94
- self . as_inner ( ) . as_fd ( )
129
+ self . as_inner ( ) . as_inner ( ) . as_fd ( )
95
130
}
96
131
}
97
132
98
133
impl From < OwnedFd > for PidFd {
99
134
fn from ( fd : OwnedFd ) -> Self {
100
- Self :: from_inner ( FileDesc :: from_inner ( fd) )
135
+ Self :: from_inner ( InnerPidFd :: from_inner ( FileDesc :: from_inner ( fd) ) )
101
136
}
102
137
}
103
138
104
139
impl From < PidFd > for OwnedFd {
105
140
fn from ( pid_fd : PidFd ) -> Self {
106
- pid_fd. into_inner ( ) . into_inner ( )
141
+ pid_fd. into_inner ( ) . into_inner ( ) . into_inner ( )
107
142
}
108
143
}
109
144
@@ -124,18 +159,26 @@ pub trait ChildExt: Sealed {
124
159
/// [`Child`]: process::Child
125
160
fn pidfd ( & self ) -> Result < & PidFd > ;
126
161
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.
128
164
///
129
165
/// A pidfd will only be available if its creation was requested with
130
166
/// [`create_pidfd`] when the corresponding [`Command`] was created.
131
167
///
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
+ ///
132
172
/// Even if requested, a pidfd may not be available due to an older
133
173
/// version of Linux being in use, or if some other error occurred.
134
174
///
135
175
/// [`Command`]: process::Command
136
176
/// [`create_pidfd`]: CommandExt::create_pidfd
177
+ /// [`pidfd`]: ChildExt::pidfd
137
178
/// [`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 ;
139
182
}
140
183
141
184
/// Os-specific extensions for [`Command`]
@@ -146,7 +189,7 @@ pub trait CommandExt: Sealed {
146
189
/// spawned by this [`Command`].
147
190
/// By default, no pidfd will be created.
148
191
///
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 `].
150
193
///
151
194
/// A pidfd will only be created if it is possible to do so
152
195
/// in a guaranteed race-free manner. Otherwise, [`pidfd`] will return an error.
@@ -160,7 +203,7 @@ pub trait CommandExt: Sealed {
160
203
/// [`Command`]: process::Command
161
204
/// [`Child`]: process::Child
162
205
/// [`pidfd`]: fn@ChildExt::pidfd
163
- /// [`take_pidfd `]: ChildExt::take_pidfd
206
+ /// [`into_pidfd `]: ChildExt::into_pidfd
164
207
fn create_pidfd ( & mut self , val : bool ) -> & mut process:: Command ;
165
208
}
166
209
0 commit comments