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?;

`