@@ -35,8 +35,20 @@ cfg_if::cfg_if! {
35
35
if #[ cfg( all( target_os = "nto" , target_env = "nto71" ) ) ] {
36
36
use crate :: thread;
37
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 ;
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 ) ;
40
52
}
41
53
}
42
54
@@ -163,12 +175,24 @@ impl Command {
163
175
unsafe fn do_fork ( & mut self ) -> Result < ( pid_t , pid_t ) , io:: Error > {
164
176
use crate :: sys:: os:: errno;
165
177
166
- let mut tries_left = MAX_FORKSPAWN_TRIES ;
178
+ let mut minimum_delay = None ;
179
+ let mut delay = MIN_FORKSPAWN_SLEEP ;
180
+
167
181
loop {
168
182
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 ;
172
196
} else {
173
197
return cvt ( r) . map ( |res| ( res, -1 ) ) ;
174
198
}
@@ -481,12 +505,22 @@ impl Command {
481
505
argv : * const * mut c_char ,
482
506
envp : * const * mut c_char ,
483
507
) -> i32 {
484
- let mut tries_left = MAX_FORKSPAWN_TRIES ;
508
+ let mut minimum_delay = None ;
509
+ let mut delay = MIN_FORKSPAWN_SLEEP ;
485
510
loop {
486
511
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 ;
490
524
continue ;
491
525
}
492
526
r => {
0 commit comments