use crate::error::SysError;
use crate::shim::{self, SigAction, SigMask};
use rustix::process::{self, Signal};
use std::time::Duration;
#[derive(PartialEq)]
pub enum SignalEvent {
Interrupt(Signal),
Quit(Signal),
Stop(Signal),
Continue(Signal),
Child(Signal),
Resize(Signal),
Unknown(Signal),
Timeout,
}
const PROCESSED_SIGNALS: [Signal; 10] = [
Signal::TERM,
Signal::INT,
Signal::HUP,
Signal::QUIT,
Signal::TSTP,
Signal::TTIN,
Signal::TTOU,
Signal::CONT,
Signal::CHILD,
Signal::WINCH,
];
fn to_event(sig: Signal) -> SignalEvent {
match sig {
Signal::TERM | Signal::INT | Signal::HUP => SignalEvent::Interrupt(sig),
Signal::QUIT => SignalEvent::Quit(sig),
Signal::TSTP | Signal::TTIN | Signal::TTOU => SignalEvent::Stop(sig),
Signal::CONT => SignalEvent::Continue(sig),
Signal::CHILD => SignalEvent::Child(sig),
Signal::WINCH => SignalEvent::Resize(sig),
_ => SignalEvent::Unknown(sig),
}
}
pub fn init_parent_signals() -> Result<(), SysError> {
if let Err(err) = shim::sigmask(&PROCESSED_SIGNALS, SigMask::Block) {
return Err(SysError("sigmask()", err));
}
for sig in PROCESSED_SIGNALS {
if let Err(err) = shim::sigaction(sig, SigAction::Default) {
return Err(SysError("sigaction()", err));
}
}
if let Err(err) = shim::sigaction(Signal::PIPE, SigAction::Ignore) {
return Err(SysError("sigaction()", err));
}
Ok(())
}
pub fn init_child_signals() -> Result<(), SysError> {
if let Err(err) = shim::sigaction(Signal::PIPE, SigAction::Default) {
return Err(SysError("sigaction()", err));
}
for sig in PROCESSED_SIGNALS {
if let Err(err) = shim::sigaction(sig, SigAction::Default) {
return Err(SysError("sigaction()", err));
}
}
if let Err(err) = shim::sigmask(&PROCESSED_SIGNALS, SigMask::Unblock) {
return Err(SysError("sigmask()", err));
}
Ok(())
}
pub fn wait_signal(timeout: Option<Duration>) -> Result<SignalEvent, SysError> {
loop {
let maybe_sig = shim::sigwait(&PROCESSED_SIGNALS, timeout)
.map_err(|err| SysError("sigwait()", err))?;
if let Some(sig) = maybe_sig {
let event = to_event(sig);
if let SignalEvent::Unknown(_) = event {
continue;
}
return Ok(event);
}
return Ok(SignalEvent::Timeout);
}
}
pub fn drop_signal(sig: Signal) -> Result<(), SysError> {
if let Err(err) = shim::sigwait(&[sig], Some(Duration::from_millis(0))) {
return Err(SysError("sigwait()", err));
}
Ok(())
}
pub fn deliver_signal(sig: Signal) -> Result<(), SysError> {
if let Err(err) = shim::sigmask(&[sig], SigMask::Unblock) {
return Err(SysError("sigmask()", err));
}
if let Err(err) = process::kill_process(process::getpid(), sig) {
return Err(SysError("kill()", err));
}
if let Err(err) = shim::sigmask(&[sig], SigMask::Block) {
return Err(SysError("sigmask()", err));
}
Ok(())
}