#![cfg_attr(docsrs, feature(doc_cfg))]
mod stdlib;
#[cfg(feature = "tokio")]
pub mod tokio;
#[doc = include_str!("../README.md")]
mod readme_tests {}
use std::io;
pub use stdlib::InterruptibleChild;
#[cfg(windows)]
const CREATE_NEW_PROCESS_GROUP: u32 = 0x00000200;
pub trait InterruptibleCommand {
type Child: Interruptible;
fn spawn_interruptible(&mut self) -> io::Result<Self::Child>;
}
pub trait Interruptible {
fn pid(&mut self) -> io::Result<Option<u32>>;
fn interrupt(&mut self) -> io::Result<()> {
match self.pid()? {
Some(pid) => inner::interrupt(pid),
None => Err(io::Error::other("Process is complete or has no pid")),
}
}
fn terminate(&mut self) -> io::Result<()> {
match self.pid()? {
Some(pid) => inner::terminate(pid),
None => Err(io::Error::other("Process is complete or has no pid")),
}
}
}
mod inner {
use std::io;
#[cfg(all(not(windows), not(unix)))]
pub fn interrupt(_pid: u32) -> io::Result<()> {
unimplemented!("'interrupt' is not implemented for this platform");
}
#[cfg(all(not(windows), not(unix)))]
pub fn terminate(_pid: u32) -> io::Result<()> {
unimplemented!("'terminate' is not implemented for this platform");
}
#[cfg(unix)]
pub fn interrupt(pid: u32) -> io::Result<()> {
send_signal(pid, libc::SIGINT)
}
#[cfg(unix)]
pub fn terminate(pid: u32) -> io::Result<()> {
send_signal(pid, libc::SIGTERM)
}
#[cfg(unix)]
fn send_signal(pid: u32, signal: i32) -> io::Result<()> {
if unsafe { libc::kill(pid as i32, signal) } == 0 {
Ok(())
} else {
Err(io::Error::last_os_error())
}
}
#[cfg(windows)]
pub fn interrupt(pid: u32) -> io::Result<()> {
generate_event(pid, windows_sys::Win32::System::Console::CTRL_C_EVENT)
}
#[cfg(windows)]
pub fn terminate(pid: u32) -> io::Result<()> {
generate_event(pid, windows_sys::Win32::System::Console::CTRL_BREAK_EVENT)
}
#[cfg(windows)]
fn generate_event(pid: u32, event: u32) -> io::Result<()> {
use windows_sys::Win32::System::Console::GenerateConsoleCtrlEvent;
if unsafe { GenerateConsoleCtrlEvent(event, pid) } != 0 {
Ok(())
} else {
Err(io::Error::last_os_error())
}
}
}