use std::process::{Command, Stdio};
use std::sync::Arc;
use std::sync::atomic::{AtomicU32, Ordering};
#[derive(Clone, Debug, Default)]
pub struct ProcessHold {
running: Arc<AtomicU32>,
}
const HOLD_SIGNAL: &str = "STOP";
const RELEASE_SIGNAL: &str = "CONT";
const END_SIGNAL: &str = "TERM";
const SIGNAL_PROGRAM: &str = "kill";
impl ProcessHold {
pub(crate) fn running(&self, process: Option<u32>) {
self.running
.store(process.unwrap_or_default(), Ordering::SeqCst);
}
#[must_use]
pub fn process(&self) -> Option<u32> {
let running = self.running.load(Ordering::SeqCst);
(running != 0).then_some(running)
}
pub fn hold(&self) -> bool {
self.signalled(HOLD_SIGNAL)
}
pub fn release(&self) -> bool {
self.signalled(RELEASE_SIGNAL)
}
pub fn cancel(&self) -> bool {
let _released = self.signalled(RELEASE_SIGNAL);
self.signalled(END_SIGNAL)
}
fn signalled(&self, signal: &str) -> bool {
let running = self.running.load(Ordering::SeqCst);
if running == 0 || !HOLDING_IS_POSSIBLE {
return false;
}
Command::new(SIGNAL_PROGRAM)
.args(["-s", signal, "--", &format!("-{running}")])
.stdout(Stdio::null())
.stderr(Stdio::null())
.status()
.is_ok_and(|status| status.success())
}
}
pub const HOLDING_IS_POSSIBLE: bool = cfg!(unix);