@@ -118,84 +118,88 @@ impl Command {
118
118
}
119
119
}
120
120
121
- // Attempts to fork the process. If successful, returns
122
- // Ok((0, -1)) in the child, and Ok((child_pid, child_pidfd)) in the parent.
121
+ // Attempts to fork the process. If successful, returns Ok((0, -1))
122
+ // in the child, and Ok((child_pid, -1)) in the parent.
123
+ #[ cfg( not( target_os = "linux" ) ) ]
124
+ fn do_fork ( & mut self ) -> Result < ( pid_t , pid_t ) , io:: Error > {
125
+ cvt ( unsafe { libc:: fork ( ) } ) . map ( |res| ( res, -1 ) )
126
+ }
127
+
128
+ // Attempts to fork the process. If successful, returns Ok((0, -1))
129
+ // in the child, and Ok((child_pid, child_pidfd)) in the parent.
130
+ #[ cfg( target_os = "linux" ) ]
123
131
fn do_fork ( & mut self ) -> Result < ( pid_t , pid_t ) , io:: Error > {
132
+ use crate :: sync:: atomic:: { AtomicBool , Ordering } ;
133
+
134
+ static HAS_CLONE3 : AtomicBool = AtomicBool :: new ( true ) ;
135
+ const CLONE_PIDFD : u64 = 0x00001000 ;
136
+
137
+ #[ repr( C ) ]
138
+ struct clone_args {
139
+ flags : u64 ,
140
+ pidfd : u64 ,
141
+ child_tid : u64 ,
142
+ parent_tid : u64 ,
143
+ exit_signal : u64 ,
144
+ stack : u64 ,
145
+ stack_size : u64 ,
146
+ tls : u64 ,
147
+ set_tid : u64 ,
148
+ set_tid_size : u64 ,
149
+ cgroup : u64 ,
150
+ }
151
+
152
+ syscall ! {
153
+ fn clone3( cl_args: * mut clone_args, len: libc:: size_t) -> libc:: c_long
154
+ }
155
+
124
156
// If we fail to create a pidfd for any reason, this will
125
- // stay as -1, which indicates an error
157
+ // stay as -1, which indicates an error.
126
158
let mut pidfd: pid_t = -1 ;
127
159
128
- // On Linux, attempt to use the `clone3` syscall, which
129
- // supports more arguments (in particular, the ability to create a pidfd).
130
- // If this fails, we will fall through this block to a call to `fork()`
131
- #[ cfg( target_os = "linux" ) ]
132
- {
133
- use crate :: sync:: atomic:: { AtomicBool , Ordering } ;
134
- static HAS_CLONE3 : AtomicBool = AtomicBool :: new ( true ) ;
135
-
136
- const CLONE_PIDFD : u64 = 0x00001000 ;
137
-
138
- #[ repr( C ) ]
139
- struct clone_args {
140
- flags : u64 ,
141
- pidfd : u64 ,
142
- child_tid : u64 ,
143
- parent_tid : u64 ,
144
- exit_signal : u64 ,
145
- stack : u64 ,
146
- stack_size : u64 ,
147
- tls : u64 ,
148
- set_tid : u64 ,
149
- set_tid_size : u64 ,
150
- cgroup : u64 ,
151
- }
152
-
153
- syscall ! {
154
- fn clone3( cl_args: * mut clone_args, len: libc:: size_t) -> libc:: c_long
160
+ // Attempt to use the `clone3` syscall, which supports more arguments
161
+ // (in particular, the ability to create a pidfd). If this fails,
162
+ // we will fall through this block to a call to `fork()`
163
+ if HAS_CLONE3 . load ( Ordering :: Relaxed ) {
164
+ let mut flags = 0 ;
165
+ if self . create_pidfd {
166
+ flags |= CLONE_PIDFD ;
155
167
}
156
168
157
- if HAS_CLONE3 . load ( Ordering :: Relaxed ) {
158
- let mut flags = 0 ;
159
- if self . create_pidfd {
160
- flags |= CLONE_PIDFD ;
161
- }
162
-
163
- let mut args = clone_args {
164
- flags,
165
- pidfd : & mut pidfd as * mut pid_t as u64 ,
166
- child_tid : 0 ,
167
- parent_tid : 0 ,
168
- exit_signal : libc:: SIGCHLD as u64 ,
169
- stack : 0 ,
170
- stack_size : 0 ,
171
- tls : 0 ,
172
- set_tid : 0 ,
173
- set_tid_size : 0 ,
174
- cgroup : 0 ,
175
- } ;
176
-
177
- let args_ptr = & mut args as * mut clone_args ;
178
- let args_size = crate :: mem:: size_of :: < clone_args > ( ) ;
179
-
180
- let res = cvt ( unsafe { clone3 ( args_ptr, args_size) } ) ;
181
- match res {
182
- Ok ( n) => return Ok ( ( n as pid_t , pidfd) ) ,
183
- Err ( e) => match e. raw_os_error ( ) {
184
- // Multiple threads can race to execute this store,
185
- // but that's fine - that just means that multiple threads
186
- // will have tried and failed to execute the same syscall,
187
- // with no other side effects.
188
- Some ( libc:: ENOSYS ) => HAS_CLONE3 . store ( false , Ordering :: Relaxed ) ,
189
- // Fallback to fork if `EPERM` is returned. (e.g. blocked by seccomp)
190
- Some ( libc:: EPERM ) => { }
191
- _ => return Err ( e) ,
192
- } ,
193
- }
169
+ let mut args = clone_args {
170
+ flags,
171
+ pidfd : & mut pidfd as * mut pid_t as u64 ,
172
+ child_tid : 0 ,
173
+ parent_tid : 0 ,
174
+ exit_signal : libc:: SIGCHLD as u64 ,
175
+ stack : 0 ,
176
+ stack_size : 0 ,
177
+ tls : 0 ,
178
+ set_tid : 0 ,
179
+ set_tid_size : 0 ,
180
+ cgroup : 0 ,
181
+ } ;
182
+
183
+ let args_ptr = & mut args as * mut clone_args ;
184
+ let args_size = crate :: mem:: size_of :: < clone_args > ( ) ;
185
+
186
+ let res = cvt ( unsafe { clone3 ( args_ptr, args_size) } ) ;
187
+ match res {
188
+ Ok ( n) => return Ok ( ( n as pid_t , pidfd) ) ,
189
+ Err ( e) => match e. raw_os_error ( ) {
190
+ // Multiple threads can race to execute this store,
191
+ // but that's fine - that just means that multiple threads
192
+ // will have tried and failed to execute the same syscall,
193
+ // with no other side effects.
194
+ Some ( libc:: ENOSYS ) => HAS_CLONE3 . store ( false , Ordering :: Relaxed ) ,
195
+ // Fallback to fork if `EPERM` is returned. (e.g. blocked by seccomp)
196
+ Some ( libc:: EPERM ) => { }
197
+ _ => return Err ( e) ,
198
+ } ,
194
199
}
195
200
}
196
201
197
- // If we get here, we are either not on Linux,
198
- // or we are on Linux and the 'clone3' syscall does not exist
202
+ // If we get here, the 'clone3' syscall does not exist
199
203
// or we do not have permission to call it
200
204
cvt ( unsafe { libc:: fork ( ) } ) . map ( |res| ( res, pidfd) )
201
205
}
0 commit comments