@@ -35,8 +35,20 @@ cfg_if::cfg_if! {
3535 if #[ cfg( all( target_os = "nto" , target_env = "nto71" ) ) ] {
3636 use crate :: thread;
3737 use libc:: { c_char, posix_spawn_file_actions_t, posix_spawnattr_t} ;
38- // arbitrary number of tries:
39- const MAX_FORKSPAWN_TRIES : u32 = 4 ;
38+ use crate :: time:: Duration ;
39+ // Get smallest amount of time we can sleep.
40+ // Return a common value if it cannot be determined.
41+ fn get_clock_resolution( ) -> Duration {
42+ let mut mindelay = libc:: timespec { tv_sec: 0 , tv_nsec: 0 } ;
43+ if unsafe { libc:: clock_getres( libc:: CLOCK_MONOTONIC , & mut mindelay) } == 0
44+ {
45+ Duration :: from_nanos( mindelay. tv_nsec as u64 )
46+ } else {
47+ Duration :: from_millis( 1 )
48+ }
49+ }
50+ // Arbitrary minimum sleep duration for retrying fork/spawn
51+ const MIN_FORKSPAWN_SLEEP : Duration = Duration :: from_nanos( 1 ) ;
4052 }
4153}
4254
@@ -163,12 +175,24 @@ impl Command {
163175 unsafe fn do_fork ( & mut self ) -> Result < ( pid_t , pid_t ) , io:: Error > {
164176 use crate :: sys:: os:: errno;
165177
166- let mut tries_left = MAX_FORKSPAWN_TRIES ;
178+ let mut minimum_delay = None ;
179+ let mut delay = MIN_FORKSPAWN_SLEEP ;
180+
167181 loop {
168182 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 ;
183+ if r == -1 as libc:: pid_t && errno ( ) as libc:: c_int == libc:: EBADF {
184+ if minimum_delay. is_none ( ) {
185+ minimum_delay = Some ( get_clock_resolution ( ) ) ;
186+ }
187+ if delay < minimum_delay. unwrap ( ) {
188+ // We cannot sleep this short (it would be longer).
189+ // Yield instead.
190+ thread:: yield_now ( ) ;
191+ } else {
192+ thread:: sleep ( delay) ;
193+ }
194+ delay *= 2 ;
195+ continue ;
172196 } else {
173197 return cvt ( r) . map ( |res| ( res, -1 ) ) ;
174198 }
@@ -481,12 +505,22 @@ impl Command {
481505 argv : * const * mut c_char ,
482506 envp : * const * mut c_char ,
483507 ) -> i32 {
484- let mut tries_left = MAX_FORKSPAWN_TRIES ;
508+ let mut minimum_delay = None ;
509+ let mut delay = MIN_FORKSPAWN_SLEEP ;
485510 loop {
486511 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 ;
512+ libc:: EBADF => {
513+ if minimum_delay. is_none ( ) {
514+ minimum_delay = Some ( get_clock_resolution ( ) ) ;
515+ }
516+ if delay < minimum_delay. unwrap ( ) {
517+ // We cannot sleep this short (it would be longer).
518+ // Yield instead.
519+ thread:: yield_now ( ) ;
520+ } else {
521+ thread:: sleep ( delay) ;
522+ }
523+ delay *= 2 ;
490524 continue ;
491525 }
492526 r => {
0 commit comments