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