use core::ffi::c_void;
use core::hint::unreachable_unchecked;
use core::mem::MaybeUninit;
use sc::syscall;
use crate::platform::{NonNegativeI32, SaMask, SigSetT, SIG_DFL, SIG_IGN};
#[repr(C)]
#[expect(clippy::struct_field_names)]
struct Sigaction {
sa_sigaction: SaSigaction,
sa_flags: i32,
sa_restorer: unsafe extern "C" fn() -> !,
sa_mask: SigSetT,
}
#[repr(C)]
#[derive(Copy, Clone)]
union SaSigaction {
value: usize,
sa_handler: unsafe extern "C" fn(i32),
sa_sigaction: unsafe extern "C" fn(i32, info: *mut SigInfo, *const c_void),
}
#[derive(Debug, Copy, Clone)]
pub enum SaSignalaction {
Dfl,
Ign,
Handler(unsafe extern "C" fn(i32)),
SigAction(unsafe extern "C" fn(i32, info: *mut SigInfo, *const c_void)),
}
#[repr(C)]
pub struct SigInfo {
pub si_signo: i32,
pub si_errno: i32,
pub si_code: i32,
pub si_trapno: i32,
pub si_pid: i32,
_pad: [i32; 27],
_align: [u64; 0],
}
unsafe extern "C" fn restorer() -> ! {
syscall!(RT_SIGRETURN);
unreachable_unchecked()
}
pub enum CatchSignal {
Int,
Term,
Hup,
Segv,
Chld,
}
impl CatchSignal {
fn into_raw(self) -> NonNegativeI32 {
match self {
CatchSignal::Int => crate::platform::SignalKind::SIGINT.0,
CatchSignal::Term => crate::platform::SignalKind::SIGTERM.0,
CatchSignal::Hup => crate::platform::SignalKind::SIGHUP.0,
CatchSignal::Segv => crate::platform::SignalKind::SIGSEGV.0,
CatchSignal::Chld => crate::platform::SignalKind::SIGCHLD.0,
}
}
}
#[expect(clippy::cast_possible_truncation)]
pub unsafe fn add_signal_action(
signal: CatchSignal,
sigaction: SaSignalaction,
) -> crate::error::Result<()> {
let mut constructed_action: MaybeUninit<Sigaction> = MaybeUninit::uninit();
let mut flags = SaMask::SA_RESTART | SaMask::SA_RESTORER;
let s_ptr = constructed_action.as_mut_ptr();
(*s_ptr).sa_mask = SigSetT::default();
(*s_ptr).sa_restorer = restorer;
(*s_ptr).sa_sigaction = match sigaction {
SaSignalaction::Dfl => SaSigaction { value: SIG_DFL },
SaSignalaction::Ign => SaSigaction { value: SIG_IGN },
SaSignalaction::Handler(sa_handler) => {
flags = SaMask(flags.bits() - SaMask::SA_SIGINFO.bits());
SaSigaction { sa_handler }
}
SaSignalaction::SigAction(sa_sigaction) => {
flags |= SaMask::SA_SIGINFO;
SaSigaction { sa_sigaction }
}
};
(*s_ptr).sa_flags = flags.bits() as i32;
let res = syscall!(
RT_SIGACTION,
signal.into_raw().value(),
constructed_action.as_ptr(),
0,
8
);
bail_on_below_zero!(res, "`RT_SIGACTION` syscall failed");
Ok(())
}