@@ -31,6 +31,15 @@ use libc::{c_int, pid_t};
3131#[ cfg( not( any( target_os = "vxworks" , target_os = "l4re" ) ) ) ]
3232use libc:: { gid_t, uid_t} ;
3333
34+ cfg_if:: cfg_if! {
35+ if #[ cfg( all( target_os = "nto" , target_env = "nto71" ) ) ] {
36+ use crate :: thread;
37+ use libc:: { c_char, posix_spawn_file_actions_t, posix_spawnattr_t} ;
38+ // arbitrary number of tries:
39+ const MAX_FORKSPAWN_TRIES : u32 = 4 ;
40+ }
41+ }
42+
3443////////////////////////////////////////////////////////////////////////////////
3544// Command
3645////////////////////////////////////////////////////////////////////////////////
@@ -141,11 +150,31 @@ impl Command {
141150
142151 // Attempts to fork the process. If successful, returns Ok((0, -1))
143152 // in the child, and Ok((child_pid, -1)) in the parent.
144- #[ cfg( not( target_os = "linux" , target_os = "nto" ) ) ]
153+ #[ cfg( not( any ( target_os = "linux" , all ( target_os = "nto" , target_env = "nto71" ) ) ) ) ]
145154 unsafe fn do_fork ( & mut self ) -> Result < ( pid_t , pid_t ) , io:: Error > {
146155 cvt ( libc:: fork ( ) ) . map ( |res| ( res, -1 ) )
147156 }
148157
158+ // On QNX Neutrino, fork can fail with EBADF in case "another thread might have opened
159+ // or closed a file descriptor while the fork() was occurring".
160+ // Documentation says "... or try calling fork() again". This is what we do here.
161+ // See also https://www.qnx.com/developers/docs/7.1/#com.qnx.doc.neutrino.lib_ref/topic/f/fork.html
162+ #[ cfg( all( target_os = "nto" , target_env = "nto71" ) ) ]
163+ unsafe fn do_fork ( & mut self ) -> Result < ( pid_t , pid_t ) , io:: Error > {
164+ use crate :: sys:: os:: errno;
165+
166+ let mut tries_left = MAX_FORKSPAWN_TRIES ;
167+ loop {
168+ let r = libc:: fork ( ) ;
169+ if r == -1 as libc:: pid_t && tries_left > 0 && errno ( ) as libc:: c_int == libc:: EBADF {
170+ thread:: yield_now ( ) ;
171+ tries_left -= 1 ;
172+ } else {
173+ return cvt ( r) . map ( |res| ( res, -1 ) ) ;
174+ }
175+ }
176+ }
177+
149178 // Attempts to fork the process. If successful, returns Ok((0, -1))
150179 // in the child, and Ok((child_pid, child_pidfd)) in the parent.
151180 #[ cfg( target_os = "linux" ) ]
@@ -439,6 +468,34 @@ impl Command {
439468 }
440469 }
441470
471+ // On QNX Neutrino, posix_spawnp can fail with EBADF in case "another thread might have opened
472+ // or closed a file descriptor while the posix_spawn() was occurring".
473+ // Documentation says "... or try calling posix_spawn() again". This is what we do here.
474+ // See also http://www.qnx.com/developers/docs/7.1/#com.qnx.doc.neutrino.lib_ref/topic/p/posix_spawn.html
475+ #[ cfg( all( target_os = "nto" , target_env = "nto71" ) ) ]
476+ unsafe fn retrying_libc_posix_spawnp (
477+ pid : * mut pid_t ,
478+ file : * const c_char ,
479+ file_actions : * const posix_spawn_file_actions_t ,
480+ attrp : * const posix_spawnattr_t ,
481+ argv : * const * mut c_char ,
482+ envp : * const * mut c_char ,
483+ ) -> i32 {
484+ let mut tries_left = MAX_FORKSPAWN_TRIES ;
485+ loop {
486+ match libc:: posix_spawnp ( pid, file, file_actions, attrp, argv, envp) {
487+ libc:: EBADF if tries_left > 0 => {
488+ thread:: yield_now ( ) ;
489+ tries_left -= 1 ;
490+ continue ;
491+ }
492+ r => {
493+ return r;
494+ }
495+ }
496+ }
497+ }
498+
442499 // Solaris, glibc 2.29+, and musl 1.24+ can set a new working directory,
443500 // and maybe others will gain this non-POSIX function too. We'll check
444501 // for this weak symbol as soon as it's needed, so we can return early
@@ -558,7 +615,12 @@ impl Command {
558615 // Make sure we synchronize access to the global `environ` resource
559616 let _env_lock = sys:: os:: env_read_lock ( ) ;
560617 let envp = envp. map ( |c| c. as_ptr ( ) ) . unwrap_or_else ( || * sys:: os:: environ ( ) as * const _ ) ;
561- cvt_nz ( libc:: posix_spawnp (
618+
619+ #[ cfg( not( target_os = "nto" ) ) ]
620+ let spawn_fn = libc:: posix_spawnp;
621+ #[ cfg( target_os = "nto" ) ]
622+ let spawn_fn = retrying_libc_posix_spawnp;
623+ cvt_nz ( spawn_fn (
562624 & mut p. pid ,
563625 self . get_program_cstr ( ) . as_ptr ( ) ,
564626 file_actions. 0 . as_ptr ( ) ,
0 commit comments