mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 14:55:26 +00:00
Retry to spawn/fork up to 3 times when it failed because of an interruption
This commit is contained in:
parent
f1a399cc40
commit
cef9d4cbc1
@ -31,6 +31,15 @@ use libc::{c_int, pid_t};
|
||||
#[cfg(not(any(target_os = "vxworks", target_os = "l4re")))]
|
||||
use libc::{gid_t, uid_t};
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Command
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@ -141,11 +150,31 @@ impl Command {
|
||||
|
||||
// Attempts to fork the process. If successful, returns Ok((0, -1))
|
||||
// in the child, and Ok((child_pid, -1)) in the parent.
|
||||
#[cfg(not(target_os = "linux", target_os = "nto"))]
|
||||
#[cfg(not(any(target_os = "linux", all(target_os = "nto", target_env = "nto71"))))]
|
||||
unsafe fn do_fork(&mut self) -> Result<(pid_t, pid_t), io::Error> {
|
||||
cvt(libc::fork()).map(|res| (res, -1))
|
||||
}
|
||||
|
||||
// On QNX Neutrino, fork can fail with EBADF in case "another thread might have opened
|
||||
// or closed a file descriptor while the fork() was occurring".
|
||||
// Documentation says "... or try calling fork() again". This is what we do here.
|
||||
// See also https://www.qnx.com/developers/docs/7.1/#com.qnx.doc.neutrino.lib_ref/topic/f/fork.html
|
||||
#[cfg(all(target_os = "nto", target_env = "nto71"))]
|
||||
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;
|
||||
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;
|
||||
} else {
|
||||
return cvt(r).map(|res| (res, -1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Attempts to fork the process. If successful, returns Ok((0, -1))
|
||||
// in the child, and Ok((child_pid, child_pidfd)) in the parent.
|
||||
#[cfg(target_os = "linux")]
|
||||
@ -439,6 +468,34 @@ impl Command {
|
||||
}
|
||||
}
|
||||
|
||||
// On QNX Neutrino, posix_spawnp can fail with EBADF in case "another thread might have opened
|
||||
// or closed a file descriptor while the posix_spawn() was occurring".
|
||||
// Documentation says "... or try calling posix_spawn() again". This is what we do here.
|
||||
// See also http://www.qnx.com/developers/docs/7.1/#com.qnx.doc.neutrino.lib_ref/topic/p/posix_spawn.html
|
||||
#[cfg(all(target_os = "nto", target_env = "nto71"))]
|
||||
unsafe fn retrying_libc_posix_spawnp(
|
||||
pid: *mut pid_t,
|
||||
file: *const c_char,
|
||||
file_actions: *const posix_spawn_file_actions_t,
|
||||
attrp: *const posix_spawnattr_t,
|
||||
argv: *const *mut c_char,
|
||||
envp: *const *mut c_char,
|
||||
) -> i32 {
|
||||
let mut tries_left = MAX_FORKSPAWN_TRIES;
|
||||
loop {
|
||||
match libc::posix_spawnp(pid, file, file_actions, attrp, argv, envp) {
|
||||
libc::EBADF if tries_left > 0 => {
|
||||
thread::yield_now();
|
||||
tries_left -= 1;
|
||||
continue;
|
||||
}
|
||||
r => {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Solaris, glibc 2.29+, and musl 1.24+ can set a new working directory,
|
||||
// and maybe others will gain this non-POSIX function too. We'll check
|
||||
// for this weak symbol as soon as it's needed, so we can return early
|
||||
@ -558,7 +615,12 @@ impl Command {
|
||||
// Make sure we synchronize access to the global `environ` resource
|
||||
let _env_lock = sys::os::env_read_lock();
|
||||
let envp = envp.map(|c| c.as_ptr()).unwrap_or_else(|| *sys::os::environ() as *const _);
|
||||
cvt_nz(libc::posix_spawnp(
|
||||
|
||||
#[cfg(not(target_os = "nto"))]
|
||||
let spawn_fn = libc::posix_spawnp;
|
||||
#[cfg(target_os = "nto")]
|
||||
let spawn_fn = retrying_libc_posix_spawnp;
|
||||
cvt_nz(spawn_fn(
|
||||
&mut p.pid,
|
||||
self.get_program_cstr().as_ptr(),
|
||||
file_actions.0.as_ptr(),
|
||||
|
Loading…
Reference in New Issue
Block a user