use std::sync::atomic::{AtomicBool, AtomicI32, Ordering};
use std::sync::{Arc, LazyLock, Mutex};
static CURRENT_CHILD_PID: LazyLock<Arc<Mutex<Option<u32>>>> =
LazyLock::new(|| Arc::new(Mutex::new(None)));
static CHILD_PID_FOR_SIGNAL: AtomicI32 = AtomicI32::new(-1);
static SIGINT_RECEIVED: AtomicBool = AtomicBool::new(false);
static SIGTSTP_RECEIVED: AtomicBool = AtomicBool::new(false);
pub fn check_and_clear_sigtstp() -> bool {
SIGTSTP_RECEIVED.swap(false, Ordering::SeqCst)
}
pub fn set_child(pid: u32) {
if let Ok(mut current_pid) = CURRENT_CHILD_PID.lock() {
*current_pid = Some(pid);
}
CHILD_PID_FOR_SIGNAL.store(pid as i32, Ordering::SeqCst);
}
pub fn kill_child() -> bool {
if let Ok(current_pid) = CURRENT_CHILD_PID.lock() {
if let Some(pid) = *current_pid {
#[cfg(unix)]
unsafe {
libc::kill(pid as i32, libc::SIGTERM) == 0
}
#[cfg(windows)]
{
use winapi::um::processthreadsapi::{OpenProcess, TerminateProcess};
use winapi::um::winnt::PROCESS_TERMINATE;
unsafe {
let handle = OpenProcess(PROCESS_TERMINATE, 0, pid);
if !handle.is_null() {
let result = TerminateProcess(handle, 1);
winapi::um::handleapi::CloseHandle(handle);
result != 0
} else {
false
}
}
}
} else {
false
}
} else {
false
}
}
pub fn clear_child() {
if let Ok(mut current_pid) = CURRENT_CHILD_PID.lock() {
*current_pid = None;
}
CHILD_PID_FOR_SIGNAL.store(-1, Ordering::SeqCst);
}
pub fn install_sigint_handler() {
#[cfg(unix)]
{
use nix::sys::signal::{self, SaFlags, SigAction, SigHandler, SigSet};
extern "C" fn handle_sigint(_: i32) {
SIGINT_RECEIVED.store(true, Ordering::SeqCst);
let pid = CHILD_PID_FOR_SIGNAL.load(Ordering::SeqCst);
if pid > 0 {
unsafe {
libc::kill(pid, libc::SIGTERM);
}
}
}
extern "C" fn handle_sigtstp(_: i32) {
SIGTSTP_RECEIVED.store(true, Ordering::SeqCst);
}
let action = SigAction::new(
SigHandler::Handler(handle_sigint),
SaFlags::SA_RESTART,
SigSet::empty(),
);
unsafe {
let _ = signal::sigaction(signal::Signal::SIGINT, &action);
}
let tstp_action = SigAction::new(
SigHandler::Handler(handle_sigtstp),
SaFlags::SA_RESTART,
SigSet::empty(),
);
unsafe {
let _ = signal::sigaction(signal::Signal::SIGTSTP, &tstp_action);
}
}
#[cfg(windows)]
{
extern "system" fn handle_sigint(_: u32) -> i32 {
SIGINT_RECEIVED.store(true, Ordering::SeqCst);
let pid = CHILD_PID_FOR_SIGNAL.load(Ordering::SeqCst);
if pid > 0 {
unsafe {
use winapi::um::processthreadsapi::{OpenProcess, TerminateProcess};
use winapi::um::winnt::PROCESS_TERMINATE;
let handle = OpenProcess(PROCESS_TERMINATE, 0, pid as u32);
if !handle.is_null() {
TerminateProcess(handle, 1);
winapi::um::handleapi::CloseHandle(handle);
}
}
}
1
}
unsafe {
winapi::um::consoleapi::SetConsoleCtrlHandler(Some(handle_sigint), 1);
}
}
}
pub fn check_and_clear_sigint() -> bool {
SIGINT_RECEIVED.swap(false, Ordering::SeqCst)
}