use crate::error::SysError;
use crate::shim::{self, SigAction, SigMask};
use rustix::process::{self, Signal};
use std::time::Duration;
const EVENT_SIGNALS: [Signal; 10] = [
Signal::TERM, Signal::INT, Signal::HUP, Signal::QUIT, Signal::TSTP, Signal::TTIN, Signal::TTOU, Signal::CONT, Signal::CHILD, Signal::WINCH, ];
#[derive(Debug, PartialEq)]
pub enum SignalEvent {
Interrupt(Signal),
Quit(Signal),
Stop(Signal),
Continue(Signal),
Child(Signal),
Resize(Signal),
Unknown(Signal),
Timeout,
}
fn to_event(sig: Signal) -> SignalEvent {
match sig {
Signal::INT | Signal::TERM => SignalEvent::Interrupt(sig),
Signal::QUIT | Signal::HUP => 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 display_name(sig: Signal) -> String {
if let Some(sig_name) = Signal::from_named_raw(sig.as_raw()) {
format!("{:?}", sig_name).replace("Signal::", "SIG")
} else {
format!("[{}]", sig.as_raw())
}
}
pub fn init_parent_signals() -> Result<(), SysError> {
if let Err(err) = shim::sigmask(&EVENT_SIGNALS, SigMask::Block) {
return Err(SysError("sigmask()", err));
}
for sig in EVENT_SIGNALS {
let action = if sig == Signal::CHILD {
SigAction::Noop
} else {
SigAction::Default
};
if let Err(err) = shim::sigaction(sig, action) {
return Err(SysError("sigaction()", err));
}
}
if let Err(err) = shim::sigmask(&[Signal::ALARM], SigMask::Block) {
return Err(SysError("sigmask()", err));
}
if let Err(err) = shim::sigaction(Signal::ALARM, SigAction::Noop) {
return Err(SysError("sigaction()", err));
}
if let Err(err) = shim::sigmask(&[Signal::PIPE], SigMask::Block) {
return Err(SysError("sigmask()", 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::sigmask(&EVENT_SIGNALS, SigMask::Unblock) {
return Err(SysError("sigmask()", err));
}
for sig in EVENT_SIGNALS {
if let Err(err) = shim::sigaction(sig, SigAction::Default) {
return Err(SysError("sigaction()", err));
}
}
if let Err(err) = shim::sigmask(&[Signal::ALARM], SigMask::Unblock) {
return Err(SysError("sigmask()", err));
}
if let Err(err) = shim::sigaction(Signal::ALARM, SigAction::Default) {
return Err(SysError("sigaction()", err));
}
if let Err(err) = shim::sigmask(&[Signal::PIPE], SigMask::Unblock) {
return Err(SysError("sigmask()", err));
}
if let Err(err) = shim::sigaction(Signal::PIPE, SigAction::Default) {
return Err(SysError("sigaction()", err));
}
Ok(())
}
pub fn unblock_signals() -> Result<(), SysError> {
if let Err(err) = shim::sigmask(&EVENT_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(&EVENT_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::ZERO)) {
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(())
}