@@ -31,6 +31,15 @@ use libc::{c_int, pid_t};
31
31
#[ cfg( not( any( target_os = "vxworks" , target_os = "l4re" ) ) ) ]
32
32
use libc:: { gid_t, uid_t} ;
33
33
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
+
34
43
////////////////////////////////////////////////////////////////////////////////
35
44
// Command
36
45
////////////////////////////////////////////////////////////////////////////////
@@ -141,11 +150,31 @@ impl Command {
141
150
142
151
// Attempts to fork the process. If successful, returns Ok((0, -1))
143
152
// 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" ) ) ) ) ]
145
154
unsafe fn do_fork ( & mut self ) -> Result < ( pid_t , pid_t ) , io:: Error > {
146
155
cvt ( libc:: fork ( ) ) . map ( |res| ( res, -1 ) )
147
156
}
148
157
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
+
149
178
// Attempts to fork the process. If successful, returns Ok((0, -1))
150
179
// in the child, and Ok((child_pid, child_pidfd)) in the parent.
151
180
#[ cfg( target_os = "linux" ) ]
@@ -439,6 +468,34 @@ impl Command {
439
468
}
440
469
}
441
470
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
+
442
499
// Solaris, glibc 2.29+, and musl 1.24+ can set a new working directory,
443
500
// and maybe others will gain this non-POSIX function too. We'll check
444
501
// for this weak symbol as soon as it's needed, so we can return early
@@ -558,7 +615,12 @@ impl Command {
558
615
// Make sure we synchronize access to the global `environ` resource
559
616
let _env_lock = sys:: os:: env_read_lock ( ) ;
560
617
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 (
562
624
& mut p. pid ,
563
625
self . get_program_cstr ( ) . as_ptr ( ) ,
564
626
file_actions. 0 . as_ptr ( ) ,
0 commit comments