diff options
| author | Florian Bartels <Florian.Bartels@elektrobit.com> | 2023-03-18 18:45:51 +0100 |
|---|---|---|
| committer | Florian Bartels <Florian.Bartels@elektrobit.com> | 2023-06-02 16:12:21 +0200 |
| commit | bdb475cf6c5712e706146635c4dd8bf6b2e506ff (patch) | |
| tree | e90149da2097dd5ae40d8fea83aad6d8b2a62022 /library/std/src | |
| parent | 0939ec13d88dfafcbb7f25314bd0d2f1519bf0d5 (diff) | |
| download | rust-bdb475cf6c5712e706146635c4dd8bf6b2e506ff.tar.gz rust-bdb475cf6c5712e706146635c4dd8bf6b2e506ff.zip | |
Retry to fork/spawn with exponential backoff
Diffstat (limited to 'library/std/src')
| -rw-r--r-- | library/std/src/sys/unix/process/process_unix.rs | 54 |
1 files changed, 44 insertions, 10 deletions
diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs index 612d43fe204..f68f2541902 100644 --- a/library/std/src/sys/unix/process/process_unix.rs +++ b/library/std/src/sys/unix/process/process_unix.rs @@ -35,8 +35,20 @@ cfg_if::cfg_if! { if #[cfg(all(target_os = "nto", target_env = "nto71"))] { use crate::thread; use libc::{c_char, posix_spawn_file_actions_t, posix_spawnattr_t}; - // arbitrary number of tries: - const MAX_FORKSPAWN_TRIES: u32 = 4; + use crate::time::Duration; + // Get smallest amount of time we can sleep. + // Return a common value if it cannot be determined. + fn get_clock_resolution() -> Duration { + let mut mindelay = libc::timespec { tv_sec: 0, tv_nsec: 0 }; + if unsafe { libc::clock_getres(libc::CLOCK_MONOTONIC, &mut mindelay) } == 0 + { + Duration::from_nanos(mindelay.tv_nsec as u64) + } else { + Duration::from_millis(1) + } + } + // Arbitrary minimum sleep duration for retrying fork/spawn + const MIN_FORKSPAWN_SLEEP: Duration = Duration::from_nanos(1); } } @@ -163,12 +175,24 @@ impl Command { unsafe fn do_fork(&mut self) -> Result<(pid_t, pid_t), io::Error> { use crate::sys::os::errno; - let mut tries_left = MAX_FORKSPAWN_TRIES; + let mut minimum_delay = None; + let mut delay = MIN_FORKSPAWN_SLEEP; + loop { let r = libc::fork(); - if r == -1 as libc::pid_t && tries_left > 0 && errno() as libc::c_int == libc::EBADF { - thread::yield_now(); - tries_left -= 1; + if r == -1 as libc::pid_t && errno() as libc::c_int == libc::EBADF { + if minimum_delay.is_none() { + minimum_delay = Some(get_clock_resolution()); + } + if delay < minimum_delay.unwrap() { + // We cannot sleep this short (it would be longer). + // Yield instead. + thread::yield_now(); + } else { + thread::sleep(delay); + } + delay *= 2; + continue; } else { return cvt(r).map(|res| (res, -1)); } @@ -481,12 +505,22 @@ impl Command { argv: *const *mut c_char, envp: *const *mut c_char, ) -> i32 { - let mut tries_left = MAX_FORKSPAWN_TRIES; + let mut minimum_delay = None; + let mut delay = MIN_FORKSPAWN_SLEEP; loop { match libc::posix_spawnp(pid, file, file_actions, attrp, argv, envp) { - libc::EBADF if tries_left > 0 => { - thread::yield_now(); - tries_left -= 1; + libc::EBADF => { + if minimum_delay.is_none() { + minimum_delay = Some(get_clock_resolution()); + } + if delay < minimum_delay.unwrap() { + // We cannot sleep this short (it would be longer). + // Yield instead. + thread::yield_now(); + } else { + thread::sleep(delay); + } + delay *= 2; continue; } r => { |
