summaryrefslogtreecommitdiffstats
path: root/library/std/src/sys/unix/process
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-19 09:26:03 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-19 09:26:03 +0000
commit9918693037dce8aa4bb6f08741b6812923486c18 (patch)
tree21d2b40bec7e6a7ea664acee056eb3d08e15a1cf /library/std/src/sys/unix/process
parentReleasing progress-linux version 1.75.0+dfsg1-5~progress7.99u1. (diff)
downloadrustc-9918693037dce8aa4bb6f08741b6812923486c18.tar.xz
rustc-9918693037dce8aa4bb6f08741b6812923486c18.zip
Merging upstream version 1.76.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'library/std/src/sys/unix/process')
-rw-r--r--library/std/src/sys/unix/process/process_common.rs9
-rw-r--r--library/std/src/sys/unix/process/process_unix.rs76
-rw-r--r--library/std/src/sys/unix/process/process_unix/tests.rs19
3 files changed, 88 insertions, 16 deletions
diff --git a/library/std/src/sys/unix/process/process_common.rs b/library/std/src/sys/unix/process/process_common.rs
index bac32d9e6..c5f04fb8b 100644
--- a/library/std/src/sys/unix/process/process_common.rs
+++ b/library/std/src/sys/unix/process/process_common.rs
@@ -24,11 +24,11 @@ cfg_if::cfg_if! {
if #[cfg(target_os = "fuchsia")] {
// fuchsia doesn't have /dev/null
} else if #[cfg(target_os = "redox")] {
- const DEV_NULL: &str = "null:\0";
+ const DEV_NULL: &CStr = c"null:";
} else if #[cfg(target_os = "vxworks")] {
- const DEV_NULL: &str = "/null\0";
+ const DEV_NULL: &CStr = c"/null";
} else {
- const DEV_NULL: &str = "/dev/null\0";
+ const DEV_NULL: &CStr = c"/dev/null";
}
}
@@ -481,8 +481,7 @@ impl Stdio {
let mut opts = OpenOptions::new();
opts.read(readable);
opts.write(!readable);
- let path = unsafe { CStr::from_ptr(DEV_NULL.as_ptr() as *const _) };
- let fd = File::open_c(&path, &opts)?;
+ let fd = File::open_c(DEV_NULL, &opts)?;
Ok((ChildStdio::Owned(fd.into_inner()), None))
}
diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs
index 72aca4e66..ee86a5f88 100644
--- a/library/std/src/sys/unix/process/process_unix.rs
+++ b/library/std/src/sys/unix/process/process_unix.rs
@@ -9,6 +9,8 @@ use core::ffi::NonZero_c_int;
#[cfg(target_os = "linux")]
use crate::os::linux::process::PidFd;
+#[cfg(target_os = "linux")]
+use crate::os::unix::io::AsRawFd;
#[cfg(any(
target_os = "macos",
@@ -696,11 +698,12 @@ impl Command {
msg.msg_iov = &mut iov as *mut _ as *mut _;
msg.msg_iovlen = 1;
- msg.msg_controllen = mem::size_of_val(&cmsg.buf) as _;
- msg.msg_control = &mut cmsg.buf as *mut _ as *mut _;
// only attach cmsg if we successfully acquired the pidfd
if pidfd >= 0 {
+ msg.msg_controllen = mem::size_of_val(&cmsg.buf) as _;
+ msg.msg_control = &mut cmsg.buf as *mut _ as *mut _;
+
let hdr = CMSG_FIRSTHDR(&mut msg as *mut _ as *mut _);
(*hdr).cmsg_level = SOL_SOCKET;
(*hdr).cmsg_type = SCM_RIGHTS;
@@ -717,7 +720,7 @@ impl Command {
// so we get a consistent SEQPACKET order
match cvt_r(|| libc::sendmsg(sock.as_raw(), &msg, 0)) {
Ok(0) => {}
- _ => rtabort!("failed to communicate with parent process"),
+ other => rtabort!("failed to communicate with parent process. {:?}", other),
}
}
}
@@ -748,7 +751,7 @@ impl Command {
msg.msg_controllen = mem::size_of::<Cmsg>() as _;
msg.msg_control = &mut cmsg as *mut _ as *mut _;
- match cvt_r(|| libc::recvmsg(sock.as_raw(), &mut msg, 0)) {
+ match cvt_r(|| libc::recvmsg(sock.as_raw(), &mut msg, libc::MSG_CMSG_CLOEXEC)) {
Err(_) => return -1,
Ok(_) => {}
}
@@ -787,7 +790,7 @@ pub struct Process {
// On Linux, stores the pidfd created for this child.
// This is None if the user did not request pidfd creation,
// or if the pidfd could not be created for some reason
- // (e.g. the `clone3` syscall was not available).
+ // (e.g. the `pidfd_open` syscall was not available).
#[cfg(target_os = "linux")]
pidfd: Option<PidFd>,
}
@@ -816,10 +819,23 @@ impl Process {
// and used for another process, and we probably shouldn't be killing
// random processes, so return Ok because the process has exited already.
if self.status.is_some() {
- Ok(())
- } else {
- cvt(unsafe { libc::kill(self.pid, libc::SIGKILL) }).map(drop)
+ return Ok(());
+ }
+ #[cfg(target_os = "linux")]
+ if let Some(pid_fd) = self.pidfd.as_ref() {
+ // pidfd_send_signal predates pidfd_open. so if we were able to get an fd then sending signals will work too
+ return cvt(unsafe {
+ libc::syscall(
+ libc::SYS_pidfd_send_signal,
+ pid_fd.as_raw_fd(),
+ libc::SIGKILL,
+ crate::ptr::null::<()>(),
+ 0,
+ )
+ })
+ .map(drop);
}
+ cvt(unsafe { libc::kill(self.pid, libc::SIGKILL) }).map(drop)
}
pub fn wait(&mut self) -> io::Result<ExitStatus> {
@@ -827,6 +843,17 @@ impl Process {
if let Some(status) = self.status {
return Ok(status);
}
+ #[cfg(target_os = "linux")]
+ if let Some(pid_fd) = self.pidfd.as_ref() {
+ let mut siginfo: libc::siginfo_t = unsafe { crate::mem::zeroed() };
+
+ cvt_r(|| unsafe {
+ libc::waitid(libc::P_PIDFD, pid_fd.as_raw_fd() as u32, &mut siginfo, libc::WEXITED)
+ })?;
+ let status = ExitStatus::from_waitid_siginfo(siginfo);
+ self.status = Some(status);
+ return Ok(status);
+ }
let mut status = 0 as c_int;
cvt_r(|| unsafe { libc::waitpid(self.pid, &mut status, 0) })?;
self.status = Some(ExitStatus::new(status));
@@ -837,6 +864,25 @@ impl Process {
if let Some(status) = self.status {
return Ok(Some(status));
}
+ #[cfg(target_os = "linux")]
+ if let Some(pid_fd) = self.pidfd.as_ref() {
+ let mut siginfo: libc::siginfo_t = unsafe { crate::mem::zeroed() };
+
+ cvt(unsafe {
+ libc::waitid(
+ libc::P_PIDFD,
+ pid_fd.as_raw_fd() as u32,
+ &mut siginfo,
+ libc::WEXITED | libc::WNOHANG,
+ )
+ })?;
+ if unsafe { siginfo.si_pid() } == 0 {
+ return Ok(None);
+ }
+ let status = ExitStatus::from_waitid_siginfo(siginfo);
+ self.status = Some(status);
+ return Ok(Some(status));
+ }
let mut status = 0 as c_int;
let pid = cvt(unsafe { libc::waitpid(self.pid, &mut status, libc::WNOHANG) })?;
if pid == 0 {
@@ -866,6 +912,20 @@ impl ExitStatus {
ExitStatus(status)
}
+ #[cfg(target_os = "linux")]
+ pub fn from_waitid_siginfo(siginfo: libc::siginfo_t) -> ExitStatus {
+ let status = unsafe { siginfo.si_status() };
+
+ match siginfo.si_code {
+ libc::CLD_EXITED => ExitStatus((status & 0xff) << 8),
+ libc::CLD_KILLED => ExitStatus(status),
+ libc::CLD_DUMPED => ExitStatus(status | 0x80),
+ libc::CLD_CONTINUED => ExitStatus(0xffff),
+ libc::CLD_STOPPED | libc::CLD_TRAPPED => ExitStatus(((status & 0xff) << 8) | 0x7f),
+ _ => unreachable!("waitid() should only return the above codes"),
+ }
+ }
+
fn exited(&self) -> bool {
libc::WIFEXITED(self.0)
}
diff --git a/library/std/src/sys/unix/process/process_unix/tests.rs b/library/std/src/sys/unix/process/process_unix/tests.rs
index 6aa79e7f9..6e952ed7c 100644
--- a/library/std/src/sys/unix/process/process_unix/tests.rs
+++ b/library/std/src/sys/unix/process/process_unix/tests.rs
@@ -64,7 +64,8 @@ fn test_command_fork_no_unwind() {
#[test]
#[cfg(target_os = "linux")]
fn test_command_pidfd() {
- use crate::os::fd::RawFd;
+ use crate::assert_matches::assert_matches;
+ use crate::os::fd::{AsRawFd, RawFd};
use crate::os::linux::process::{ChildExt, CommandExt};
use crate::process::Command;
@@ -78,10 +79,22 @@ fn test_command_pidfd() {
};
// always exercise creation attempts
- let child = Command::new("echo").create_pidfd(true).spawn().unwrap();
+ let mut child = Command::new("false").create_pidfd(true).spawn().unwrap();
// but only check if we know that the kernel supports pidfds
if pidfd_open_available {
- assert!(child.pidfd().is_ok())
+ assert!(child.pidfd().is_ok());
}
+ if let Ok(pidfd) = child.pidfd() {
+ let flags = super::cvt(unsafe { libc::fcntl(pidfd.as_raw_fd(), libc::F_GETFD) }).unwrap();
+ assert!(flags & libc::FD_CLOEXEC != 0);
+ }
+ let status = child.wait().expect("error waiting on pidfd");
+ assert_eq!(status.code(), Some(1));
+
+ let mut child = Command::new("sleep").arg("1000").create_pidfd(true).spawn().unwrap();
+ assert_matches!(child.try_wait(), Ok(None));
+ child.kill().expect("failed to kill child");
+ let status = child.wait().expect("error waiting on pidfd");
+ assert_eq!(status.signal(), Some(libc::SIGKILL));
}