@@ -36,19 +36,25 @@ cfg_if::cfg_if! {
36
36
use crate :: thread;
37
37
use libc:: { c_char, posix_spawn_file_actions_t, posix_spawnattr_t} ;
38
38
use crate :: time:: Duration ;
39
+ use crate :: sync:: LazyLock ;
39
40
// Get smallest amount of time we can sleep.
40
41
// Return a common value if it cannot be determined.
41
42
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
- }
43
+ static MIN_DELAY : LazyLock <Duration , fn ( ) -> Duration > = LazyLock :: new( || {
44
+ let mut mindelay = libc:: timespec { tv_sec: 0 , tv_nsec: 0 } ;
45
+ if unsafe { libc:: clock_getres( libc:: CLOCK_MONOTONIC , & mut mindelay) } == 0
46
+ {
47
+ Duration :: from_nanos( mindelay. tv_nsec as u64 )
48
+ } else {
49
+ Duration :: from_millis( 1 )
50
+ }
51
+ } ) ;
52
+ * MIN_DELAY
49
53
}
50
54
// Arbitrary minimum sleep duration for retrying fork/spawn
51
55
const MIN_FORKSPAWN_SLEEP : Duration = Duration :: from_nanos( 1 ) ;
56
+ // Maximum duration of sleeping before giving up and returning an error
57
+ const MAX_FORKSPAWN_SLEEP : Duration = Duration :: from_millis( 1000 ) ;
52
58
}
53
59
}
54
60
@@ -175,21 +181,22 @@ impl Command {
175
181
unsafe fn do_fork ( & mut self ) -> Result < ( pid_t , pid_t ) , io:: Error > {
176
182
use crate :: sys:: os:: errno;
177
183
178
- let mut minimum_delay = None ;
179
184
let mut delay = MIN_FORKSPAWN_SLEEP ;
180
185
181
186
loop {
182
187
let r = libc:: fork ( ) ;
183
188
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 ( ) {
189
+ if delay < get_clock_resolution ( ) {
188
190
// We cannot sleep this short (it would be longer).
189
191
// Yield instead.
190
192
thread:: yield_now ( ) ;
191
- } else {
193
+ } else if delay < MAX_FORKSPAWN_SLEEP {
192
194
thread:: sleep ( delay) ;
195
+ } else {
196
+ return Err ( io:: const_io_error!(
197
+ ErrorKind :: WouldBlock ,
198
+ "forking returned EBADF too often" ,
199
+ ) ) ;
193
200
}
194
201
delay *= 2 ;
195
202
continue ;
@@ -504,27 +511,28 @@ impl Command {
504
511
attrp : * const posix_spawnattr_t ,
505
512
argv : * const * mut c_char ,
506
513
envp : * const * mut c_char ,
507
- ) -> i32 {
508
- let mut minimum_delay = None ;
514
+ ) -> io:: Result < i32 > {
509
515
let mut delay = MIN_FORKSPAWN_SLEEP ;
510
516
loop {
511
517
match libc:: posix_spawnp ( pid, file, file_actions, attrp, argv, envp) {
512
518
libc:: EBADF => {
513
- if minimum_delay. is_none ( ) {
514
- minimum_delay = Some ( get_clock_resolution ( ) ) ;
515
- }
516
- if delay < minimum_delay. unwrap ( ) {
519
+ if delay < get_clock_resolution ( ) {
517
520
// We cannot sleep this short (it would be longer).
518
521
// Yield instead.
519
522
thread:: yield_now ( ) ;
520
- } else {
523
+ } else if delay < MAX_FORKSPAWN_SLEEP {
521
524
thread:: sleep ( delay) ;
525
+ } else {
526
+ return Err ( io:: const_io_error!(
527
+ ErrorKind :: WouldBlock ,
528
+ "posix_spawnp returned EBADF too often" ,
529
+ ) ) ;
522
530
}
523
531
delay *= 2 ;
524
532
continue ;
525
533
}
526
534
r => {
527
- return r ;
535
+ return Ok ( r ) ;
528
536
}
529
537
}
530
538
}
@@ -654,14 +662,20 @@ impl Command {
654
662
let spawn_fn = libc:: posix_spawnp;
655
663
#[ cfg( target_os = "nto" ) ]
656
664
let spawn_fn = retrying_libc_posix_spawnp;
657
- cvt_nz ( spawn_fn (
665
+
666
+ let spawn_res = spawn_fn (
658
667
& mut p. pid ,
659
668
self . get_program_cstr ( ) . as_ptr ( ) ,
660
669
file_actions. 0 . as_ptr ( ) ,
661
670
attrs. 0 . as_ptr ( ) ,
662
671
self . get_argv ( ) . as_ptr ( ) as * const _ ,
663
672
envp as * const _ ,
664
- ) ) ?;
673
+ ) ;
674
+
675
+ #[ cfg( target_os = "nto" ) ]
676
+ let spawn_res = spawn_res?;
677
+
678
+ cvt_nz ( spawn_res) ?;
665
679
Ok ( Some ( p) )
666
680
}
667
681
}
0 commit comments