use core::ffi::c_ulong;
use bitflags::bitflags;
use linux_raw_sys::{
general::{
__kernel_sighandler_t, __sigrestore_t, SA_NODEFER, SA_ONSTACK, SA_RESETHAND, SA_RESTART,
SA_SIGINFO, kernel_sigaction,
},
signal_macros::sig_ign,
};
use crate::{SignalSet, Signo};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DefaultSignalAction {
Terminate,
Ignore,
CoreDump,
Stop,
Continue,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SignalOSAction {
Terminate,
CoreDump,
Stop,
Continue,
NoFurtherAction,
}
bitflags! {
#[derive(Default, Debug, Clone, Copy)]
pub struct SignalActionFlags: c_ulong {
const SIGINFO = SA_SIGINFO as _;
const NODEFER = SA_NODEFER as _;
const RESETHAND = SA_RESETHAND as _;
const RESTART = SA_RESTART as _;
const ONSTACK = SA_ONSTACK as _;
const RESTORER = 0x4000000;
}
}
#[derive(Debug, Clone, Copy)]
#[repr(C)]
#[allow(non_camel_case_types)]
pub struct k_sigaction {
handler: __kernel_sighandler_t,
flags: c_ulong,
restorer: __sigrestore_t,
pub mask: SignalSet,
}
#[derive(Debug, Default, Clone)]
pub enum SignalDisposition {
#[default]
Default,
Ignore,
Handler(unsafe extern "C" fn(i32)),
}
#[derive(Debug, Clone, Default)]
pub struct SignalAction {
pub flags: SignalActionFlags,
pub mask: SignalSet,
pub disposition: SignalDisposition,
pub restorer: __sigrestore_t,
}
impl SignalAction {
pub fn is_ignore(&self, signo: Signo) -> bool {
match self.disposition {
SignalDisposition::Ignore => true,
SignalDisposition::Default => {
matches!(signo.default_action(), DefaultSignalAction::Ignore)
}
SignalDisposition::Handler(_) => false,
}
}
pub fn is_restartable(&self) -> bool {
self.flags.contains(SignalActionFlags::RESTART)
}
}
impl From<SignalAction> for kernel_sigaction {
fn from(value: SignalAction) -> Self {
let mut result: kernel_sigaction = unsafe { core::mem::zeroed() };
result.sa_flags = value.flags.bits() as _;
result.sa_mask = value.mask.into();
match &value.disposition {
SignalDisposition::Default => {
result.sa_handler_kernel = None;
}
SignalDisposition::Ignore => {
result.sa_handler_kernel = sig_ign();
}
SignalDisposition::Handler(handler) => {
result.sa_handler_kernel = Some(*handler);
}
}
#[cfg(sa_restorer)]
{
result.sa_restorer = value.restorer;
}
result
}
}
impl From<kernel_sigaction> for SignalAction {
fn from(value: kernel_sigaction) -> Self {
let flags = SignalActionFlags::from_bits_truncate(value.sa_flags);
let disposition = {
match value.sa_handler_kernel {
None => {
SignalDisposition::Default
}
Some(h) if h as usize == 1 => {
SignalDisposition::Ignore
}
Some(h) => {
SignalDisposition::Handler(h)
}
}
};
#[cfg(sa_restorer)]
let restorer = if flags.contains(SignalActionFlags::RESTORER) {
value.sa_restorer
} else {
None
};
#[cfg(not(sa_restorer))]
let restorer = None;
SignalAction {
flags,
mask: value.sa_mask.into(),
disposition,
restorer,
}
}
}