mirror of
https://github.com/rust-lang/rust.git
synced 2026-05-21 17:52:12 +03:00
Rollup merge of #156539 - jmillikin:unix-childext-killpg, r=nia-e
Add `ChildExt::kill_process_group` ACP: https://github.com/rust-lang/libs-team/issues/791 Tracking issue: https://github.com/rust-lang/rust/issues/156537
This commit is contained in:
@@ -420,6 +420,68 @@ pub trait ChildExt: Sealed {
|
||||
/// }
|
||||
/// ```
|
||||
fn send_signal(&self, signal: i32) -> io::Result<()>;
|
||||
|
||||
/// Sends a signal to a child process's process group.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function will return an error if the signal is invalid or if the
|
||||
/// child process does not have a process group. The integer values
|
||||
/// associated with signals are implementation-specific, so it's encouraged
|
||||
/// to use a crate that provides posix bindings.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// #![feature(unix_send_signal)]
|
||||
///
|
||||
/// use std::{io, os::unix::process::{ChildExt, CommandExt}, process::{Command, Stdio}};
|
||||
///
|
||||
/// use libc::SIGTERM;
|
||||
///
|
||||
/// fn main() -> io::Result<()> {
|
||||
/// # if cfg!(not(all(target_vendor = "apple", not(target_os = "macos")))) {
|
||||
/// let child = Command::new("cat")
|
||||
/// .stdin(Stdio::piped())
|
||||
/// .process_group(0)
|
||||
/// .spawn()?;
|
||||
/// child.send_process_group_signal(SIGTERM)?;
|
||||
/// # }
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
#[unstable(feature = "unix_send_signal", issue = "141975")]
|
||||
fn send_process_group_signal(&self, signal: i32) -> io::Result<()>;
|
||||
|
||||
/// Forces the child process's process group to exit.
|
||||
///
|
||||
/// This is analogous to [`Child::kill`] but applies to every process in
|
||||
/// the child process's process group.
|
||||
///
|
||||
/// Use [`CommandExt::process_group`] to assign a child process to an
|
||||
/// existing process group, or to make it the leader of a new process group.
|
||||
/// By default spawned processes are in the parent's process group.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// #![feature(unix_kill_process_group)]
|
||||
///
|
||||
/// use std::{os::unix::process::{ChildExt, CommandExt}, process::{Command, Stdio}};
|
||||
///
|
||||
/// fn main() -> std::io::Result<()> {
|
||||
/// let mut child = Command::new("cat")
|
||||
/// .stdin(Stdio::piped())
|
||||
/// .process_group(0)
|
||||
/// .spawn()?;
|
||||
/// child.kill_process_group()?;
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// [`Child::kill`]: process::Child::kill
|
||||
#[unstable(feature = "unix_kill_process_group", issue = "156537")]
|
||||
fn kill_process_group(&mut self) -> io::Result<()>;
|
||||
}
|
||||
|
||||
#[unstable(feature = "unix_send_signal", issue = "141975")]
|
||||
@@ -427,6 +489,14 @@ impl ChildExt for process::Child {
|
||||
fn send_signal(&self, signal: i32) -> io::Result<()> {
|
||||
self.handle.send_signal(signal)
|
||||
}
|
||||
|
||||
fn send_process_group_signal(&self, signal: i32) -> io::Result<()> {
|
||||
self.handle.send_process_group_signal(signal)
|
||||
}
|
||||
|
||||
fn kill_process_group(&mut self) -> io::Result<()> {
|
||||
self.handle.send_process_group_signal(libc::SIGKILL)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "process_extensions", since = "1.2.0")]
|
||||
|
||||
@@ -95,6 +95,21 @@ pub(crate) fn send_signal(&self, signal: i32) -> io::Result<()> {
|
||||
.map(drop)
|
||||
}
|
||||
|
||||
pub(crate) fn send_process_group_signal(&self, signal: i32) -> io::Result<()> {
|
||||
// since kernel 6.9
|
||||
// https://lore.kernel.org/all/20240210-chihuahua-hinzog-3945b6abd44a@brauner/
|
||||
cvt(unsafe {
|
||||
libc::syscall(
|
||||
libc::SYS_pidfd_send_signal,
|
||||
self.0.as_raw_fd(),
|
||||
signal,
|
||||
crate::ptr::null::<()>(),
|
||||
libc::PIDFD_SIGNAL_PROCESS_GROUP,
|
||||
)
|
||||
})
|
||||
.map(drop)
|
||||
}
|
||||
|
||||
pub fn wait(&self) -> io::Result<ExitStatus> {
|
||||
let r = self.waitid(libc::WEXITED)?;
|
||||
match r {
|
||||
|
||||
@@ -158,6 +158,11 @@ pub fn send_signal(&self, _signal: i32) -> io::Result<()> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub fn send_process_group_signal(&self, _signal: i32) -> io::Result<()> {
|
||||
// Fuchsia doesn't have a direct equivalent for signals
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub fn wait(&mut self) -> io::Result<ExitStatus> {
|
||||
let mut proc_info: zx_info_process_t = Default::default();
|
||||
let mut actual: size_t = 0;
|
||||
|
||||
@@ -1002,6 +1002,19 @@ pub(crate) fn send_signal(&self, signal: i32) -> io::Result<()> {
|
||||
cvt(unsafe { libc::kill(self.pid, signal) }).map(drop)
|
||||
}
|
||||
|
||||
pub(crate) fn send_process_group_signal(&self, signal: i32) -> io::Result<()> {
|
||||
// See note in `send_signal` regarding recycled PIDs.
|
||||
if self.status.is_some() {
|
||||
return Ok(());
|
||||
}
|
||||
#[cfg(target_os = "linux")]
|
||||
if let Some(pid_fd) = self.pidfd.as_ref() {
|
||||
// The `PIDFD_SIGNAL_PROCESS_GROUP` flag requires kernel >= 6.9
|
||||
return pid_fd.send_process_group_signal(signal);
|
||||
}
|
||||
cvt(unsafe { libc::killpg(self.pid, signal) }).map(drop)
|
||||
}
|
||||
|
||||
pub fn wait(&mut self) -> io::Result<ExitStatus> {
|
||||
use crate::sys::cvt_r;
|
||||
if let Some(status) = self.status {
|
||||
|
||||
@@ -49,6 +49,10 @@ pub fn send_signal(&self, _signal: i32) -> io::Result<()> {
|
||||
unsupported()
|
||||
}
|
||||
|
||||
pub fn send_process_group_signal(&self, _signal: i32) -> io::Result<()> {
|
||||
unsupported()
|
||||
}
|
||||
|
||||
pub fn wait(&mut self) -> io::Result<ExitStatus> {
|
||||
unsupported()
|
||||
}
|
||||
|
||||
@@ -161,6 +161,14 @@ pub fn send_signal(&self, signal: i32) -> io::Result<()> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn send_process_group_signal(&self, signal: i32) -> io::Result<()> {
|
||||
// See note in `send_signal` regarding recycled PIDs.
|
||||
if self.status.is_some() {
|
||||
return Ok(());
|
||||
}
|
||||
cvt(unsafe { libc::killpg(self.pid, signal) }).map(drop)
|
||||
}
|
||||
|
||||
pub fn wait(&mut self) -> io::Result<ExitStatus> {
|
||||
use crate::sys::cvt_r;
|
||||
if let Some(status) = self.status {
|
||||
|
||||
Reference in New Issue
Block a user