about summary refs log tree commit diff
path: root/library/std/src
diff options
context:
space:
mode:
authorFlorian Bartels <Florian.Bartels@elektrobit.com>2023-03-18 18:45:51 +0100
committerFlorian Bartels <Florian.Bartels@elektrobit.com>2023-06-02 16:12:21 +0200
commitbdb475cf6c5712e706146635c4dd8bf6b2e506ff (patch)
treee90149da2097dd5ae40d8fea83aad6d8b2a62022 /library/std/src
parent0939ec13d88dfafcbb7f25314bd0d2f1519bf0d5 (diff)
downloadrust-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.rs54
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 => {