Rollup merge of #141990 - Qelxiros:141975-unix_send_signal, r=ChrisDenton,tgross35
Implement send_signal for unix child processes Tracking issue: rust-lang/rust#141975 There are two main differences between my implementation and the Public API section of the tracking issue. ~First, `send_signal` requires a mutable reference, like `Child::kill`.~ Second, `ChildExt` has `Sealed` as a supertrait, bringing it more in line with other extension traits like `CommandExt`. try-job: `dist-various*` try-job: `test-various*`
This commit is contained in:
commit
e381a14b7c
7 changed files with 67 additions and 8 deletions
|
|
@ -116,6 +116,9 @@ pub mod prelude {
|
|||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use super::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
|
||||
#[doc(no_inline)]
|
||||
#[unstable(feature = "unix_send_signal", issue = "141975")]
|
||||
pub use super::process::ChildExt;
|
||||
#[doc(no_inline)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use super::process::{CommandExt, ExitStatusExt};
|
||||
#[doc(no_inline)]
|
||||
|
|
|
|||
|
|
@ -378,6 +378,41 @@ impl ExitStatusExt for process::ExitStatusError {
|
|||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "unix_send_signal", issue = "141975")]
|
||||
pub trait ChildExt: Sealed {
|
||||
/// Sends a signal to a child process.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function will return an error if the signal is invalid. The integer values associated
|
||||
/// with signals are implemenation-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, process::{Command, Stdio}};
|
||||
///
|
||||
/// use libc::SIGTERM;
|
||||
///
|
||||
/// fn main() -> io::Result<()> {
|
||||
/// let child = Command::new("cat").stdin(Stdio::piped()).spawn()?;
|
||||
/// child.send_signal(SIGTERM)?;
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
fn send_signal(&self, signal: i32) -> io::Result<()>;
|
||||
}
|
||||
|
||||
#[unstable(feature = "unix_send_signal", issue = "141975")]
|
||||
impl ChildExt for process::Child {
|
||||
fn send_signal(&self, signal: i32) -> io::Result<()> {
|
||||
self.handle.send_signal(signal)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "process_extensions", since = "1.2.0")]
|
||||
impl FromRawFd for process::Stdio {
|
||||
#[inline]
|
||||
|
|
|
|||
|
|
@ -13,11 +13,15 @@ pub(crate) struct PidFd(FileDesc);
|
|||
|
||||
impl PidFd {
|
||||
pub fn kill(&self) -> io::Result<()> {
|
||||
self.send_signal(libc::SIGKILL)
|
||||
}
|
||||
|
||||
pub(crate) fn send_signal(&self, signal: i32) -> io::Result<()> {
|
||||
cvt(unsafe {
|
||||
libc::syscall(
|
||||
libc::SYS_pidfd_send_signal,
|
||||
self.0.as_raw_fd(),
|
||||
libc::SIGKILL,
|
||||
signal,
|
||||
crate::ptr::null::<()>(),
|
||||
0,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -152,6 +152,11 @@ impl Process {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn send_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;
|
||||
|
|
|
|||
|
|
@ -963,9 +963,13 @@ impl Process {
|
|||
self.pid as u32
|
||||
}
|
||||
|
||||
pub fn kill(&mut self) -> io::Result<()> {
|
||||
pub fn kill(&self) -> io::Result<()> {
|
||||
self.send_signal(libc::SIGKILL)
|
||||
}
|
||||
|
||||
pub(crate) fn send_signal(&self, signal: i32) -> io::Result<()> {
|
||||
// If we've already waited on this process then the pid can be recycled
|
||||
// and used for another process, and we probably shouldn't be killing
|
||||
// and used for another process, and we probably shouldn't be signaling
|
||||
// random processes, so return Ok because the process has exited already.
|
||||
if self.status.is_some() {
|
||||
return Ok(());
|
||||
|
|
@ -973,9 +977,9 @@ impl Process {
|
|||
#[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 pid_fd.kill();
|
||||
return pid_fd.send_signal(signal);
|
||||
}
|
||||
cvt(unsafe { libc::kill(self.pid, libc::SIGKILL) }).map(drop)
|
||||
cvt(unsafe { libc::kill(self.pid, signal) }).map(drop)
|
||||
}
|
||||
|
||||
pub fn wait(&mut self) -> io::Result<ExitStatus> {
|
||||
|
|
|
|||
|
|
@ -40,7 +40,11 @@ impl Process {
|
|||
0
|
||||
}
|
||||
|
||||
pub fn kill(&mut self) -> io::Result<()> {
|
||||
pub fn kill(&self) -> io::Result<()> {
|
||||
unsupported()
|
||||
}
|
||||
|
||||
pub fn send_signal(&self, _signal: i32) -> io::Result<()> {
|
||||
unsupported()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -146,14 +146,18 @@ impl Process {
|
|||
self.pid as u32
|
||||
}
|
||||
|
||||
pub fn kill(&mut self) -> io::Result<()> {
|
||||
pub fn kill(&self) -> io::Result<()> {
|
||||
self.send_signal(libc::SIGKILL)
|
||||
}
|
||||
|
||||
pub fn send_signal(&self, signal: i32) -> io::Result<()> {
|
||||
// If we've already waited on this process then the pid can be recycled
|
||||
// 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)
|
||||
cvt(unsafe { libc::kill(self.pid, signal) }).map(drop)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue