Auto merge of #81825 - voidc:pidfd, r=joshtriplett
Add Linux-specific pidfd process extensions (take 2) Continuation of #77168. I addressed the following concerns from the original PR: - make `CommandExt` and `ChildExt` sealed traits - wrap file descriptors in `PidFd` struct representing ownership over the fd - add `take_pidfd` to take the fd out of `Child` - close fd when dropped Tracking Issue: #82971
This commit is contained in:
commit
4e21ef2a4e
8 changed files with 410 additions and 11 deletions
45
src/test/ui/command/command-create-pidfd.rs
Normal file
45
src/test/ui/command/command-create-pidfd.rs
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
// run-pass
|
||||
// only-linux - pidfds are a linux-specific concept
|
||||
|
||||
#![feature(linux_pidfd)]
|
||||
#![feature(rustc_private)]
|
||||
|
||||
extern crate libc;
|
||||
|
||||
use std::io::Error;
|
||||
use std::os::linux::process::{ChildExt, CommandExt};
|
||||
use std::process::Command;
|
||||
|
||||
fn has_clone3() -> bool {
|
||||
let res = unsafe { libc::syscall(libc::SYS_clone3, 0, 0) };
|
||||
let err = (res == -1)
|
||||
.then(|| Error::last_os_error())
|
||||
.expect("probe syscall should not succeed");
|
||||
err.raw_os_error() != Some(libc::ENOSYS)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// pidfds require the clone3 syscall
|
||||
if !has_clone3() {
|
||||
return;
|
||||
}
|
||||
|
||||
// We don't assert the precise value, since the standard library
|
||||
// might have opened other file descriptors before our code runs.
|
||||
let _ = Command::new("echo")
|
||||
.create_pidfd(true)
|
||||
.spawn()
|
||||
.unwrap()
|
||||
.pidfd().expect("failed to obtain pidfd");
|
||||
|
||||
let _ = Command::new("echo")
|
||||
.create_pidfd(false)
|
||||
.spawn()
|
||||
.unwrap()
|
||||
.pidfd().expect_err("pidfd should not have been created when create_pid(false) is set");
|
||||
|
||||
let _ = Command::new("echo")
|
||||
.spawn()
|
||||
.unwrap()
|
||||
.pidfd().expect_err("pidfd should not have been created");
|
||||
}
|
||||
|
|
@ -8,8 +8,6 @@
|
|||
// ignore-sgx no processes
|
||||
#![feature(process_exec, rustc_private)]
|
||||
|
||||
extern crate libc;
|
||||
|
||||
use std::env;
|
||||
use std::io::Error;
|
||||
use std::os::unix::process::CommandExt;
|
||||
|
|
@ -17,6 +15,23 @@ use std::process::Command;
|
|||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use std::sync::Arc;
|
||||
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
fn getpid() -> u32 {
|
||||
use std::process;
|
||||
process::id()
|
||||
}
|
||||
|
||||
/// We need to directly use the getpid syscall instead of using `process::id()`
|
||||
/// because the libc wrapper might return incorrect values after a process was
|
||||
/// forked.
|
||||
#[cfg(target_os = "linux")]
|
||||
fn getpid() -> u32 {
|
||||
extern crate libc;
|
||||
unsafe {
|
||||
libc::syscall(libc::SYS_getpid) as _
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
if let Some(arg) = env::args().nth(1) {
|
||||
match &arg[..] {
|
||||
|
|
@ -68,14 +83,12 @@ fn main() {
|
|||
};
|
||||
assert_eq!(output.raw_os_error(), Some(102));
|
||||
|
||||
let pid = unsafe { libc::getpid() };
|
||||
assert!(pid >= 0);
|
||||
let pid = getpid();
|
||||
let output = unsafe {
|
||||
Command::new(&me)
|
||||
.arg("empty")
|
||||
.pre_exec(move || {
|
||||
let child = libc::getpid();
|
||||
assert!(child >= 0);
|
||||
let child = getpid();
|
||||
assert!(pid != child);
|
||||
Ok(())
|
||||
})
|
||||
|
|
|
|||
|
|
@ -23,6 +23,21 @@ use std::sync::atomic::{AtomicU32, Ordering};
|
|||
|
||||
use libc::c_int;
|
||||
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
fn getpid() -> u32 {
|
||||
process::id()
|
||||
}
|
||||
|
||||
/// We need to directly use the getpid syscall instead of using `process::id()`
|
||||
/// because the libc wrapper might return incorrect values after a process was
|
||||
/// forked.
|
||||
#[cfg(target_os = "linux")]
|
||||
fn getpid() -> u32 {
|
||||
unsafe {
|
||||
libc::syscall(libc::SYS_getpid) as _
|
||||
}
|
||||
}
|
||||
|
||||
/// This stunt allocator allows us to spot heap allocations in the child.
|
||||
struct PidChecking<A> {
|
||||
parent: A,
|
||||
|
|
@ -44,7 +59,7 @@ impl<A> PidChecking<A> {
|
|||
fn check(&self) {
|
||||
let require_pid = self.require_pid.load(Ordering::Acquire);
|
||||
if require_pid != 0 {
|
||||
let actual_pid = process::id();
|
||||
let actual_pid = getpid();
|
||||
if require_pid != actual_pid {
|
||||
unsafe {
|
||||
libc::raise(libc::SIGUSR1);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue