pub(crate) fn prepare_command_for_signalling(
command: &mut tokio::process::Command,
) -> &mut tokio::process::Command {
#[cfg(windows)]
{
use windows_sys::Win32::System::Threading::CREATE_NEW_PROCESS_GROUP;
command.creation_flags(CREATE_NEW_PROCESS_GROUP)
}
#[cfg(unix)]
{
command.process_group(0)
}
#[cfg(all(not(windows), not(unix)))]
{
command
}
}
#[cfg(unix)]
pub(crate) const INTERRUPT_SIGNAL_NAME: &str = "SIGINT";
#[cfg(windows)]
pub(crate) const INTERRUPT_SIGNAL_NAME: &str = "CTRL_BREAK_EVENT";
#[cfg(all(not(windows), not(unix)))]
pub(crate) const INTERRUPT_SIGNAL_NAME: &str = "interrupt";
#[cfg(unix)]
pub(crate) const TERMINATE_SIGNAL_NAME: &str = "SIGTERM";
#[cfg(windows)]
pub(crate) const TERMINATE_SIGNAL_NAME: &str = "CTRL_BREAK_EVENT";
#[cfg(all(not(windows), not(unix)))]
pub(crate) const TERMINATE_SIGNAL_NAME: &str = "terminate";
#[cfg(unix)]
pub(crate) const KILL_SIGNAL_NAME: &str = "SIGKILL";
#[cfg(windows)]
pub(crate) const KILL_SIGNAL_NAME: &str = "TerminateProcess";
#[cfg(all(not(windows), not(unix)))]
pub(crate) const KILL_SIGNAL_NAME: &str = "kill";
pub(crate) fn send_interrupt(child: &tokio::process::Child) -> std::io::Result<()> {
let Some(pid) = child.id() else {
return Ok(());
};
#[cfg(unix)]
{
send_to_process_group(pid, nix::sys::signal::Signal::SIGINT)
}
#[cfg(windows)]
{
use windows_sys::Win32::System::Console::CTRL_BREAK_EVENT;
use windows_sys::Win32::System::Console::GenerateConsoleCtrlEvent;
let success = unsafe { GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, pid) };
if success == 0 {
return Err(std::io::Error::last_os_error());
}
Ok(())
}
#[cfg(all(not(windows), not(unix)))]
{
panic!("Cannot send interrupt signal to process. Platform is unsupported.")
}
}
pub(crate) fn send_terminate(child: &tokio::process::Child) -> std::io::Result<()> {
let Some(pid) = child.id() else {
return Ok(());
};
#[cfg(unix)]
{
send_to_process_group(pid, nix::sys::signal::Signal::SIGTERM)
}
#[cfg(windows)]
{
use windows_sys::Win32::System::Console::CTRL_BREAK_EVENT;
use windows_sys::Win32::System::Console::GenerateConsoleCtrlEvent;
let success = unsafe { GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, pid) };
if success == 0 {
return Err(std::io::Error::last_os_error());
}
Ok(())
}
#[cfg(all(not(windows), not(unix)))]
{
panic!("Cannot send termination signal to process. Platform is unsupported.")
}
}
#[cfg(unix)]
fn send_to_process_group(pid: u32, signal: nix::sys::signal::Signal) -> std::io::Result<()> {
use nix::sys::signal;
use nix::unistd::Pid;
signal::killpg(Pid::from_raw(pid.cast_signed()), signal).map_err(std::io::Error::other)?;
Ok(())
}
#[cfg(unix)]
pub(crate) fn send_kill_to_process_group(pid: u32) -> std::io::Result<()> {
send_to_process_group(pid, nix::sys::signal::Signal::SIGKILL)
}