@@ -36,19 +36,25 @@ cfg_if::cfg_if! {
3636 use crate :: thread;
3737 use libc:: { c_char, posix_spawn_file_actions_t, posix_spawnattr_t} ;
3838 use crate :: time:: Duration ;
39+ use crate :: sync:: LazyLock ;
3940 // Get smallest amount of time we can sleep.
4041 // Return a common value if it cannot be determined.
4142 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
4953 }
5054 // Arbitrary minimum sleep duration for retrying fork/spawn
5155 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 ) ;
5258 }
5359}
5460
@@ -175,21 +181,22 @@ impl Command {
175181 unsafe fn do_fork ( & mut self ) -> Result < ( pid_t , pid_t ) , io:: Error > {
176182 use crate :: sys:: os:: errno;
177183
178- let mut minimum_delay = None ;
179184 let mut delay = MIN_FORKSPAWN_SLEEP ;
180185
181186 loop {
182187 let r = libc:: fork ( ) ;
183188 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 ( ) {
188190 // We cannot sleep this short (it would be longer).
189191 // Yield instead.
190192 thread:: yield_now ( ) ;
191- } else {
193+ } else if delay < MAX_FORKSPAWN_SLEEP {
192194 thread:: sleep ( delay) ;
195+ } else {
196+ return Err ( io:: const_io_error!(
197+ ErrorKind :: WouldBlock ,
198+ "forking returned EBADF too often" ,
199+ ) ) ;
193200 }
194201 delay *= 2 ;
195202 continue ;
@@ -504,27 +511,28 @@ impl Command {
504511 attrp : * const posix_spawnattr_t ,
505512 argv : * const * mut c_char ,
506513 envp : * const * mut c_char ,
507- ) -> i32 {
508- let mut minimum_delay = None ;
514+ ) -> io:: Result < i32 > {
509515 let mut delay = MIN_FORKSPAWN_SLEEP ;
510516 loop {
511517 match libc:: posix_spawnp ( pid, file, file_actions, attrp, argv, envp) {
512518 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 ( ) {
517520 // We cannot sleep this short (it would be longer).
518521 // Yield instead.
519522 thread:: yield_now ( ) ;
520- } else {
523+ } else if delay < MAX_FORKSPAWN_SLEEP {
521524 thread:: sleep ( delay) ;
525+ } else {
526+ return Err ( io:: const_io_error!(
527+ ErrorKind :: WouldBlock ,
528+ "posix_spawnp returned EBADF too often" ,
529+ ) ) ;
522530 }
523531 delay *= 2 ;
524532 continue ;
525533 }
526534 r => {
527- return r ;
535+ return Ok ( r ) ;
528536 }
529537 }
530538 }
@@ -654,14 +662,20 @@ impl Command {
654662 let spawn_fn = libc:: posix_spawnp;
655663 #[ cfg( target_os = "nto" ) ]
656664 let spawn_fn = retrying_libc_posix_spawnp;
657- cvt_nz ( spawn_fn (
665+
666+ let spawn_res = spawn_fn (
658667 & mut p. pid ,
659668 self . get_program_cstr ( ) . as_ptr ( ) ,
660669 file_actions. 0 . as_ptr ( ) ,
661670 attrs. 0 . as_ptr ( ) ,
662671 self . get_argv ( ) . as_ptr ( ) as * const _ ,
663672 envp as * const _ ,
664- ) ) ?;
673+ ) ;
674+
675+ #[ cfg( target_os = "nto" ) ]
676+ let spawn_res = spawn_res?;
677+
678+ cvt_nz ( spawn_res) ?;
665679 Ok ( Some ( p) )
666680 }
667681 }
0 commit comments