more fine-grained feature-detection for pidfd spawning · model-checking/verify-rust-std@4c9a96e (original) (raw)
`@@ -476,35 +476,47 @@ impl Command {
`
476
476
``
477
477
` weak! { fn pidfd_getpid(libc::c_int) -> libc::c_int }
`
478
478
``
479
``
`-
static PIDFD_SPAWN_SUPPORTED: AtomicU8 = AtomicU8::new(0);
`
``
479
`+
static PIDFD_SUPPORTED: AtomicU8 = AtomicU8::new(0);
`
480
480
`const UNKNOWN: u8 = 0;
`
481
``
`-
const YES: u8 = 1;
`
482
``
`-
// NO currently forces a fallback to fork/exec. We could be more nuanced here and keep using spawn
`
483
``
`-
// if we know pidfd's aren't supported at all and the fallback would be futile.
`
484
``
`-
const NO: u8 = 2;
`
``
481
`+
const SPAWN: u8 = 1;
`
``
482
`+
// Obtaining a pidfd via the fork+exec path might work
`
``
483
`+
const FORK_EXEC: u8 = 2;
`
``
484
`+
// Neither pidfd_spawn nor fork/exec will get us a pidfd.
`
``
485
`+
// Instead we'll just posix_spawn if the other preconditions are met.
`
``
486
`+
const NO: u8 = 3;
`
485
487
``
486
488
`if self.get_create_pidfd() {
`
487
``
`-
let flag = PIDFD_SPAWN_SUPPORTED.load(Ordering::Relaxed);
`
488
``
`-
if flag == NO || pidfd_spawnp.get().is_none() || pidfd_getpid.get().is_none() {
`
``
489
`+
let mut support = PIDFD_SUPPORTED.load(Ordering::Relaxed);
`
``
490
`+
if support == FORK_EXEC {
`
489
491
`return Ok(None);
`
490
492
`}
`
491
``
`-
if flag == UNKNOWN {
`
492
``
`-
let mut support = NO;
`
``
493
`+
if support == UNKNOWN {
`
``
494
`+
support = NO;
`
493
495
`let our_pid = crate::process::id();
`
494
``
`-
let pidfd =
`
495
``
`-
unsafe { libc::syscall(libc::SYS_pidfd_open, our_pid, 0) } as libc::c_int;
`
496
``
`-
if pidfd >= 0 {
`
497
``
`-
let pid = unsafe { pidfd_getpid.get().unwrap()(pidfd) } as u32;
`
498
``
`-
unsafe { libc::close(pidfd) };
`
499
``
`-
if pid == our_pid {
`
500
``
`-
support = YES
`
501
``
`-
};
`
``
496
`+
let pidfd = cvt(unsafe { libc::syscall(libc::SYS_pidfd_open, our_pid, 0) } as c_int);
`
``
497
`+
match pidfd {
`
``
498
`+
Ok(pidfd) => {
`
``
499
`+
support = FORK_EXEC;
`
``
500
`+
if let Some(Ok(pid)) = pidfd_getpid.get().map(|f| cvt(unsafe { f(pidfd) } as i32)) {
`
``
501
`+
if pidfd_spawnp.get().is_some() && pid as u32 == our_pid {
`
``
502
`+
support = SPAWN
`
``
503
`+
}
`
``
504
`+
}
`
``
505
`+
unsafe { libc::close(pidfd) };
`
``
506
`+
}
`
``
507
`+
Err(e) if e.raw_os_error() == Some(libc::EMFILE) => {
`
``
508
`+
// We're temporarily(?) out of file descriptors. In this case obtaining a pidfd would also fail
`
``
509
`+
// Don't update the support flag so we can probe again later.
`
``
510
`+
return Err(e)
`
``
511
`+
}
`
``
512
`+
_ => {}
`
502
513
`}
`
503
``
`-
PIDFD_SPAWN_SUPPORTED.store(support, Ordering::Relaxed);
`
504
``
`-
if support != YES {
`
``
514
`+
PIDFD_SUPPORTED.store(support, Ordering::Relaxed);
`
``
515
`+
if support == FORK_EXEC {
`
505
516
`return Ok(None);
`
506
517
`}
`
507
518
`}
`
``
519
`+
core::assert_matches::debug_assert_matches!(support, SPAWN | NO);
`
508
520
`}
`
509
521
`} else {
`
510
522
`if self.get_create_pidfd() {
`
`@@ -691,7 +703,7 @@ impl Command {
`
691
703
`let spawn_fn = retrying_libc_posix_spawnp;
`
692
704
``
693
705
`#[cfg(target_os = "linux")]
`
694
``
`-
if self.get_create_pidfd() {
`
``
706
`+
if self.get_create_pidfd() && PIDFD_SUPPORTED.load(Ordering::Relaxed) == SPAWN {
`
695
707
`let mut pidfd: libc::c_int = -1;
`
696
708
`let spawn_res = pidfd_spawnp.get().unwrap()(
`
697
709
`&mut pidfd,
`
`@@ -706,7 +718,7 @@ impl Command {
`
706
718
`if let Err(ref e) = spawn_res
`
707
719
` && e.raw_os_error() == Some(libc::ENOSYS)
`
708
720
`{
`
709
``
`-
PIDFD_SPAWN_SUPPORTED.store(NO, Ordering::Relaxed);
`
``
721
`+
PIDFD_SUPPORTED.store(FORK_EXEC, Ordering::Relaxed);
`
710
722
`return Ok(None);
`
711
723
`}
`
712
724
` spawn_res?;
`