@@ -118,84 +118,88 @@ impl Command {
118118 }
119119 }
120120
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" ) ]
123131 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+
124156 // 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.
126158 let mut pidfd: pid_t = -1 ;
127159
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 ;
155167 }
156168
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+ } ,
194199 }
195200 }
196201
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
199203 // or we do not have permission to call it
200204 cvt ( unsafe { libc:: fork ( ) } ) . map ( |res| ( res, pidfd) )
201205 }
0 commit comments