about summary refs log tree commit diff
path: root/library/std/src/sys/unix/process/process_unix.rs
diff options
context:
space:
mode:
authorFlorian Bartels <Florian.Bartels@elektrobit.com>2023-06-02 17:52:14 +0200
committerFlorian Bartels <Florian.Bartels@elektrobit.com>2023-06-02 17:52:14 +0200
commit716cc5ac938ad0a5302fe924a7142c0cc1d7d515 (patch)
tree10e2cee8c5f0b56870c6369a9a3476fa81980c65 /library/std/src/sys/unix/process/process_unix.rs
parentd8f21101ec383d33c68f1867faf2ba74b3dca1a8 (diff)
downloadrust-716cc5ac938ad0a5302fe924a7142c0cc1d7d515.tar.gz
rust-716cc5ac938ad0a5302fe924a7142c0cc1d7d515.zip
Only determine clock res once; give up before sleeping more than 1 second
Diffstat (limited to 'library/std/src/sys/unix/process/process_unix.rs')
-rw-r--r--library/std/src/sys/unix/process/process_unix.rs60
1 files changed, 37 insertions, 23 deletions
diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs
index f68f2541902..3721988b405 100644
--- a/library/std/src/sys/unix/process/process_unix.rs
+++ b/library/std/src/sys/unix/process/process_unix.rs
@@ -36,19 +36,25 @@ cfg_if::cfg_if! {
         use crate::thread;
         use libc::{c_char, posix_spawn_file_actions_t, posix_spawnattr_t};
         use crate::time::Duration;
+        use crate::sync::LazyLock;
         // 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)
-            }
+            static MIN_DELAY: LazyLock<Duration, fn() -> Duration> = LazyLock::new(|| {
+                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)
+                }
+            });
+            *MIN_DELAY
         }
         // Arbitrary minimum sleep duration for retrying fork/spawn
         const MIN_FORKSPAWN_SLEEP: Duration = Duration::from_nanos(1);
+        // Maximum duration of sleeping before giving up and returning an error
+        const MAX_FORKSPAWN_SLEEP: Duration = Duration::from_millis(1000);
     }
 }
 
@@ -175,21 +181,22 @@ impl Command {
     unsafe fn do_fork(&mut self) -> Result<(pid_t, pid_t), io::Error> {
         use crate::sys::os::errno;
 
-        let mut minimum_delay = None;
         let mut delay = MIN_FORKSPAWN_SLEEP;
 
         loop {
             let r = libc::fork();
             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() {
+                if delay < get_clock_resolution() {
                     // We cannot sleep this short (it would be longer).
                     // Yield instead.
                     thread::yield_now();
-                } else {
+                } else if delay < MAX_FORKSPAWN_SLEEP {
                     thread::sleep(delay);
+                } else {
+                    return Err(io::const_io_error!(
+                        ErrorKind::WouldBlock,
+                        "forking returned EBADF too often",
+                    ));
                 }
                 delay *= 2;
                 continue;
@@ -504,27 +511,28 @@ impl Command {
             attrp: *const posix_spawnattr_t,
             argv: *const *mut c_char,
             envp: *const *mut c_char,
-        ) -> i32 {
-            let mut minimum_delay = None;
+        ) -> io::Result<i32> {
             let mut delay = MIN_FORKSPAWN_SLEEP;
             loop {
                 match libc::posix_spawnp(pid, file, file_actions, attrp, argv, envp) {
                     libc::EBADF => {
-                        if minimum_delay.is_none() {
-                            minimum_delay = Some(get_clock_resolution());
-                        }
-                        if delay < minimum_delay.unwrap() {
+                        if delay < get_clock_resolution() {
                             // We cannot sleep this short (it would be longer).
                             // Yield instead.
                             thread::yield_now();
-                        } else {
+                        } else if delay < MAX_FORKSPAWN_SLEEP {
                             thread::sleep(delay);
+                        } else {
+                            return Err(io::const_io_error!(
+                                ErrorKind::WouldBlock,
+                                "posix_spawnp returned EBADF too often",
+                            ));
                         }
                         delay *= 2;
                         continue;
                     }
                     r => {
-                        return r;
+                        return Ok(r);
                     }
                 }
             }
@@ -654,14 +662,20 @@ impl Command {
             let spawn_fn = libc::posix_spawnp;
             #[cfg(target_os = "nto")]
             let spawn_fn = retrying_libc_posix_spawnp;
-            cvt_nz(spawn_fn(
+
+            let spawn_res = spawn_fn(
                 &mut p.pid,
                 self.get_program_cstr().as_ptr(),
                 file_actions.0.as_ptr(),
                 attrs.0.as_ptr(),
                 self.get_argv().as_ptr() as *const _,
                 envp as *const _,
-            ))?;
+            );
+
+            #[cfg(target_os = "nto")]
+            let spawn_res = spawn_res?;
+
+            cvt_nz(spawn_res)?;
             Ok(Some(p))
         }
     }