use bytemuck::TransparentWrapper;
use linux_syscall::syscall;
use linux_syscall::Result as LinuxSyscallResult;
use num_enum::{IntoPrimitive, TryFromPrimitive};
use shadow_pod::Pod;
use vasi::VirtualAddressSpaceIndependent;
use crate::bindings::{self, linux_sigval};
use crate::const_conversions;
use crate::const_conversions::i32_from_u32_allowing_wraparound;
use crate::errno::Errno;
use crate::posix_types::kernel_pid_t;
use crate::posix_types::Pid;
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[repr(transparent)]
pub struct Signal(i32);
#[derive(Debug, Copy, Clone)]
pub struct SignalFromI32Error(pub i32);
impl TryFrom<i32> for Signal {
type Error = SignalFromI32Error;
fn try_from(value: i32) -> Result<Self, Self::Error> {
if (1..=i32::from(Signal::SIGRT_MAX)).contains(&value) {
Ok(Self(value))
} else {
Err(SignalFromI32Error(value))
}
}
}
impl From<Signal> for i32 {
fn from(value: Signal) -> Self {
value.as_i32()
}
}
impl Signal {
pub const SIGHUP: Self = Self::std_from_u32_const(bindings::LINUX_SIGHUP);
pub const SIGINT: Self = Self::std_from_u32_const(bindings::LINUX_SIGINT);
pub const SIGQUIT: Self = Self::std_from_u32_const(bindings::LINUX_SIGQUIT);
pub const SIGILL: Self = Self::std_from_u32_const(bindings::LINUX_SIGILL);
pub const SIGTRAP: Self = Self::std_from_u32_const(bindings::LINUX_SIGTRAP);
pub const SIGABRT: Self = Self::std_from_u32_const(bindings::LINUX_SIGABRT);
pub const SIGBUS: Self = Self::std_from_u32_const(bindings::LINUX_SIGBUS);
pub const SIGFPE: Self = Self::std_from_u32_const(bindings::LINUX_SIGFPE);
pub const SIGKILL: Self = Self::std_from_u32_const(bindings::LINUX_SIGKILL);
pub const SIGUSR1: Self = Self::std_from_u32_const(bindings::LINUX_SIGUSR1);
pub const SIGSEGV: Self = Self::std_from_u32_const(bindings::LINUX_SIGSEGV);
pub const SIGUSR2: Self = Self::std_from_u32_const(bindings::LINUX_SIGUSR2);
pub const SIGPIPE: Self = Self::std_from_u32_const(bindings::LINUX_SIGPIPE);
pub const SIGALRM: Self = Self::std_from_u32_const(bindings::LINUX_SIGALRM);
pub const SIGTERM: Self = Self::std_from_u32_const(bindings::LINUX_SIGTERM);
pub const SIGSTKFLT: Self = Self::std_from_u32_const(bindings::LINUX_SIGSTKFLT);
pub const SIGCHLD: Self = Self::std_from_u32_const(bindings::LINUX_SIGCHLD);
pub const SIGCONT: Self = Self::std_from_u32_const(bindings::LINUX_SIGCONT);
pub const SIGSTOP: Self = Self::std_from_u32_const(bindings::LINUX_SIGSTOP);
pub const SIGTSTP: Self = Self::std_from_u32_const(bindings::LINUX_SIGTSTP);
pub const SIGTTIN: Self = Self::std_from_u32_const(bindings::LINUX_SIGTTIN);
pub const SIGTTOU: Self = Self::std_from_u32_const(bindings::LINUX_SIGTTOU);
pub const SIGURG: Self = Self::std_from_u32_const(bindings::LINUX_SIGURG);
pub const SIGXCPU: Self = Self::std_from_u32_const(bindings::LINUX_SIGXCPU);
pub const SIGXFSZ: Self = Self::std_from_u32_const(bindings::LINUX_SIGXFSZ);
pub const SIGVTALRM: Self = Self::std_from_u32_const(bindings::LINUX_SIGVTALRM);
pub const SIGPROF: Self = Self::std_from_u32_const(bindings::LINUX_SIGPROF);
pub const SIGWINCH: Self = Self::std_from_u32_const(bindings::LINUX_SIGWINCH);
pub const SIGIO: Self = Self::std_from_u32_const(bindings::LINUX_SIGIO);
pub const SIGPWR: Self = Self::std_from_u32_const(bindings::LINUX_SIGPWR);
pub const SIGSYS: Self = Self::std_from_u32_const(bindings::LINUX_SIGSYS);
pub const STANDARD_MAX: Self = Self(31);
pub const SIGRT_MIN: Self = Self::rt_from_u32_const(bindings::LINUX_SIGRTMIN);
pub const SIGRT_MAX: Self = Self::rt_from_u32_const(64);
pub const MIN: Self = Self(1);
pub const MAX: Self = Self::SIGRT_MAX;
pub const SIGIOT: Self = Self::std_from_u32_const(bindings::LINUX_SIGIOT);
pub const SIGPOLL: Self = Self::std_from_u32_const(bindings::LINUX_SIGPOLL);
pub const SIGUNUSED: Self = Self::std_from_u32_const(bindings::LINUX_SIGUNUSED);
pub fn is_realtime(&self) -> bool {
(i32::from(Self::SIGRT_MIN)..=i32::from(Self::SIGRT_MAX)).contains(&self.0)
}
pub const fn as_i32(&self) -> i32 {
self.0
}
pub fn standard_signals() -> impl Iterator<Item = Signal> {
(i32::from(Self::MIN)..=i32::from(Self::STANDARD_MAX)).map(|i| Self::try_from(i).unwrap())
}
const fn std_from_u32_const(val: u32) -> Self {
let rv = Self(const_conversions::i32_from_u32(val));
assert!(rv.0 as u32 == val);
assert!(rv.0 <= Self::STANDARD_MAX.0);
rv
}
const fn rt_from_u32_const(val: u32) -> Self {
let rv = Self(const_conversions::i32_from_u32(val));
assert!(rv.0 as u32 == val);
assert!(rv.0 > Self::STANDARD_MAX.0);
rv
}
pub fn as_raw(this: Option<Self>) -> i32 {
this.map(|s| s.as_i32()).unwrap_or(0)
}
}
bitflags::bitflags! {
#[repr(transparent)]
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
pub struct SigActionFlags: u64 {
const SA_NOCLDSTOP = const_conversions::u64_from_u32(bindings::LINUX_SA_NOCLDSTOP);
const SA_NOCLDWAIT = const_conversions::u64_from_u32(bindings::LINUX_SA_NOCLDWAIT);
const SA_NODEFER = const_conversions::u64_from_u32(bindings::LINUX_SA_NODEFER);
const SA_ONSTACK = const_conversions::u64_from_u32(bindings::LINUX_SA_ONSTACK);
const SA_RESETHAND = const_conversions::u64_from_u32(bindings::LINUX_SA_RESETHAND);
const SA_RESTART = const_conversions::u64_from_u32(bindings::LINUX_SA_RESTART);
const SA_RESTORER = const_conversions::u64_from_u32(bindings::LINUX_SA_RESTORER);
const SA_SIGINFO = const_conversions::u64_from_u32(bindings::LINUX_SA_SIGINFO);
}
}
unsafe impl VirtualAddressSpaceIndependent for SigActionFlags {}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum SigInfoCode {
Si(SigInfoCodeSi),
Ill(SigInfoCodeIll),
Fpe(SigInfoCodeFpe),
Segv(SigInfoCodeSegv),
Bus(SigInfoCodeBus),
Trap(SigInfoCodeTrap),
Cld(SigInfoCodeCld),
Poll(SigInfoCodePoll),
Sys(SigInfoCodeSys),
}
#[derive(Debug, Copy, Clone)]
pub struct SigInfoCodeFromRawError {
pub code: i32,
pub signo: i32,
}
impl SigInfoCode {
fn try_from_raw(raw_code: i32, raw_signo: i32) -> Result<Self, SigInfoCodeFromRawError> {
if let Ok(si_code) = SigInfoCodeSi::try_from(raw_code) {
return Ok(SigInfoCode::Si(si_code));
}
let err = SigInfoCodeFromRawError {
code: raw_code,
signo: raw_signo,
};
let Ok(signal) = Signal::try_from(raw_signo) else {
return Err(err);
};
match signal {
Signal::SIGCHLD => SigInfoCodeCld::try_from(raw_code)
.map(SigInfoCode::Cld)
.or(Err(err)),
Signal::SIGILL => SigInfoCodeIll::try_from(raw_code)
.map(SigInfoCode::Ill)
.or(Err(err)),
Signal::SIGFPE => SigInfoCodeFpe::try_from(raw_code)
.map(SigInfoCode::Fpe)
.or(Err(err)),
Signal::SIGSEGV => SigInfoCodeSegv::try_from(raw_code)
.map(SigInfoCode::Segv)
.or(Err(err)),
Signal::SIGBUS => SigInfoCodeBus::try_from(raw_code)
.map(SigInfoCode::Bus)
.or(Err(err)),
Signal::SIGTRAP => SigInfoCodeTrap::try_from(raw_code)
.map(SigInfoCode::Trap)
.or(Err(err)),
Signal::SIGPOLL => SigInfoCodePoll::try_from(raw_code)
.map(SigInfoCode::Poll)
.or(Err(err)),
Signal::SIGSYS => SigInfoCodeSys::try_from(raw_code)
.map(SigInfoCode::Sys)
.or(Err(err)),
_ => Err(err),
}
}
}
#[allow(non_camel_case_types)]
#[repr(i32)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)]
pub enum SigInfoCodeSi {
SI_USER = const_conversions::i32_from_u32(bindings::LINUX_SI_USER),
SI_KERNEL = const_conversions::i32_from_u32(bindings::LINUX_SI_KERNEL),
SI_QUEUE = bindings::LINUX_SI_QUEUE,
SI_TIMER = bindings::LINUX_SI_TIMER,
SI_MESGQ = bindings::LINUX_SI_MESGQ,
SI_ASYNCIO = bindings::LINUX_SI_ASYNCIO,
SI_TKILL = bindings::LINUX_SI_TKILL,
}
#[allow(non_camel_case_types)]
#[repr(i32)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)]
pub enum SigInfoCodeCld {
CLD_EXITED = const_conversions::i32_from_u32(bindings::LINUX_CLD_EXITED),
CLD_KILLED = const_conversions::i32_from_u32(bindings::LINUX_CLD_KILLED),
CLD_DUMPED = const_conversions::i32_from_u32(bindings::LINUX_CLD_DUMPED),
CLD_TRAPPED = const_conversions::i32_from_u32(bindings::LINUX_CLD_TRAPPED),
CLD_STOPPED = const_conversions::i32_from_u32(bindings::LINUX_CLD_STOPPED),
CLD_CONTINUED = const_conversions::i32_from_u32(bindings::LINUX_CLD_CONTINUED),
}
#[allow(non_camel_case_types)]
#[repr(i32)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)]
pub enum SigInfoCodeIll {
ILL_ILLOPC = const_conversions::i32_from_u32(bindings::LINUX_ILL_ILLOPC),
ILL_ILLOPN = const_conversions::i32_from_u32(bindings::LINUX_ILL_ILLOPN),
ILL_ILLADR = const_conversions::i32_from_u32(bindings::LINUX_ILL_ILLADR),
ILL_ILLTRP = const_conversions::i32_from_u32(bindings::LINUX_ILL_ILLTRP),
ILL_PRVOPC = const_conversions::i32_from_u32(bindings::LINUX_ILL_PRVOPC),
ILL_PRVREG = const_conversions::i32_from_u32(bindings::LINUX_ILL_PRVREG),
ILL_COPROC = const_conversions::i32_from_u32(bindings::LINUX_ILL_COPROC),
ILL_BADSTK = const_conversions::i32_from_u32(bindings::LINUX_ILL_BADSTK),
ILL_BADIADDR = const_conversions::i32_from_u32(bindings::LINUX_ILL_BADIADDR),
}
#[allow(non_camel_case_types)]
#[repr(i32)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)]
pub enum SigInfoCodeFpe {
FPE_INTDIV = const_conversions::i32_from_u32(bindings::LINUX_FPE_INTDIV),
FPE_INTOVF = const_conversions::i32_from_u32(bindings::LINUX_FPE_INTOVF),
FPE_FLTDIV = const_conversions::i32_from_u32(bindings::LINUX_FPE_FLTDIV),
FPE_FLTOVF = const_conversions::i32_from_u32(bindings::LINUX_FPE_FLTOVF),
FPE_FLTUND = const_conversions::i32_from_u32(bindings::LINUX_FPE_FLTUND),
FPE_FLTRES = const_conversions::i32_from_u32(bindings::LINUX_FPE_FLTRES),
FPE_FLTINV = const_conversions::i32_from_u32(bindings::LINUX_FPE_FLTINV),
FPE_FLTSUB = const_conversions::i32_from_u32(bindings::LINUX_FPE_FLTSUB),
FPE_FLTUNK = const_conversions::i32_from_u32(bindings::LINUX_FPE_FLTUNK),
FPE_CONDTRAP = const_conversions::i32_from_u32(bindings::LINUX_FPE_CONDTRAP),
}
#[allow(non_camel_case_types)]
#[repr(i32)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)]
pub enum SigInfoCodeSegv {
SEGV_MAPERR = const_conversions::i32_from_u32(bindings::LINUX_SEGV_MAPERR),
SEGV_ACCERR = const_conversions::i32_from_u32(bindings::LINUX_SEGV_ACCERR),
SEGV_BNDERR = const_conversions::i32_from_u32(bindings::LINUX_SEGV_BNDERR),
SEGV_PKUERR = const_conversions::i32_from_u32(bindings::LINUX_SEGV_PKUERR),
SEGV_ACCADI = const_conversions::i32_from_u32(bindings::LINUX_SEGV_ACCADI),
SEGV_ADIDERR = const_conversions::i32_from_u32(bindings::LINUX_SEGV_ADIDERR),
SEGV_ADIPERR = const_conversions::i32_from_u32(bindings::LINUX_SEGV_ADIPERR),
SEGV_MTEAERR = const_conversions::i32_from_u32(bindings::LINUX_SEGV_MTEAERR),
SEGV_MTESERR = const_conversions::i32_from_u32(bindings::LINUX_SEGV_MTESERR),
}
#[allow(non_camel_case_types)]
#[repr(i32)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)]
pub enum SigInfoCodeBus {
BUS_ADRALN = const_conversions::i32_from_u32(bindings::LINUX_BUS_ADRALN),
BUS_ADRERR = const_conversions::i32_from_u32(bindings::LINUX_BUS_ADRERR),
BUS_OBJERR = const_conversions::i32_from_u32(bindings::LINUX_BUS_OBJERR),
BUS_MCEERR_AR = const_conversions::i32_from_u32(bindings::LINUX_BUS_MCEERR_AR),
BUS_MCEERR_AO = const_conversions::i32_from_u32(bindings::LINUX_BUS_MCEERR_AO),
}
#[allow(non_camel_case_types)]
#[repr(i32)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)]
pub enum SigInfoCodeTrap {
TRAP_BRKPT = const_conversions::i32_from_u32(bindings::LINUX_TRAP_BRKPT),
TRAP_TRACE = const_conversions::i32_from_u32(bindings::LINUX_TRAP_TRACE),
TRAP_BRANCH = const_conversions::i32_from_u32(bindings::LINUX_TRAP_BRANCH),
TRAP_HWBKPT = const_conversions::i32_from_u32(bindings::LINUX_TRAP_HWBKPT),
TRAP_UNK = const_conversions::i32_from_u32(bindings::LINUX_TRAP_UNK),
TRAP_PERF = const_conversions::i32_from_u32(bindings::LINUX_TRAP_PERF),
}
#[allow(non_camel_case_types)]
#[repr(i32)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)]
pub enum SigInfoCodePoll {
POLL_IN = const_conversions::i32_from_u32(bindings::LINUX_POLL_IN),
POLL_OUT = const_conversions::i32_from_u32(bindings::LINUX_POLL_OUT),
POLL_MSG = const_conversions::i32_from_u32(bindings::LINUX_POLL_MSG),
POLL_ERR = const_conversions::i32_from_u32(bindings::LINUX_POLL_ERR),
POLL_PRI = const_conversions::i32_from_u32(bindings::LINUX_POLL_PRI),
POLL_HUP = const_conversions::i32_from_u32(bindings::LINUX_POLL_HUP),
}
#[allow(non_camel_case_types)]
#[repr(i32)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)]
pub enum SigInfoCodeSys {
SYS_SECCOMP = const_conversions::i32_from_u32(bindings::LINUX_SYS_SECCOMP),
}
#[allow(non_camel_case_types)]
pub type linux_siginfo_t = bindings::linux_siginfo_t;
type SigInfoDetailsFields = bindings::linux___sifields;
pub type SigInfoDetailsKill = bindings::linux___sifields__bindgen_ty_1;
pub type SigInfoDetailsTimer = bindings::linux___sifields__bindgen_ty_2;
pub type SigInfoDetailsRt = bindings::linux___sifields__bindgen_ty_3;
pub type SigInfoDetailsSigChld = bindings::linux___sifields__bindgen_ty_4;
pub type SigInfoDetailsSigFault = bindings::linux___sifields__bindgen_ty_5;
pub type SigInfoDetailsSigPoll = bindings::linux___sifields__bindgen_ty_6;
pub type SigInfoDetailsSigSys = bindings::linux___sifields__bindgen_ty_7;
pub enum SigInfoDetails {
Kill(SigInfoDetailsKill),
Timer(SigInfoDetailsTimer),
Rt(SigInfoDetailsRt),
SigChld(SigInfoDetailsSigChld),
SigFault(SigInfoDetailsSigFault),
SigPoll(SigInfoDetailsSigPoll),
SigSys(SigInfoDetailsSigSys),
}
#[derive(Copy, Clone, Debug)]
#[repr(transparent)]
#[allow(non_camel_case_types)]
pub struct siginfo_t(linux_siginfo_t);
unsafe impl Send for siginfo_t {}
unsafe impl Pod for siginfo_t {}
impl siginfo_t {
fn inner(&self) -> &bindings::linux_siginfo__bindgen_ty_1__bindgen_ty_1 {
unsafe { &self.0.l__bindgen_anon_1.l__bindgen_anon_1 }
}
pub unsafe fn wrap_assume_initd(si: linux_siginfo_t) -> Self {
Self(si)
}
pub unsafe fn wrap_ref_assume_initd(si: &linux_siginfo_t) -> &Self {
unsafe { &*(core::ptr::from_ref(si) as *const Self) }
}
pub unsafe fn wrap_mut_assume_initd(si: &mut linux_siginfo_t) -> &mut Self {
unsafe { &mut *(core::ptr::from_mut(si) as *mut Self) }
}
pub unsafe fn peel(si: Self) -> linux_siginfo_t {
si.0
}
#[inline]
pub fn signal(&self) -> Result<Signal, SignalFromI32Error> {
Signal::try_from(self.inner().lsi_signo)
}
#[inline]
pub fn code(&self) -> Result<SigInfoCode, SigInfoCodeFromRawError> {
SigInfoCode::try_from_raw(self.inner().lsi_code, self.inner().lsi_signo)
}
pub unsafe fn details(&self) -> Option<SigInfoDetails> {
let Ok(code) = self.code() else {
return None;
};
match code {
SigInfoCode::Si(SigInfoCodeSi::SI_USER) => Some(SigInfoDetails::Kill(unsafe {
self.inner().l_sifields.l_kill
})),
SigInfoCode::Si(SigInfoCodeSi::SI_KERNEL) => Some(SigInfoDetails::SigFault(unsafe {
self.inner().l_sifields.l_sigfault
})),
SigInfoCode::Si(SigInfoCodeSi::SI_QUEUE) => {
Some(SigInfoDetails::Rt(unsafe { self.inner().l_sifields.l_rt }))
}
SigInfoCode::Si(SigInfoCodeSi::SI_TIMER) => Some(SigInfoDetails::Timer(unsafe {
self.inner().l_sifields.l_timer
})),
SigInfoCode::Si(SigInfoCodeSi::SI_MESGQ) => {
Some(SigInfoDetails::Rt(unsafe { self.inner().l_sifields.l_rt }))
}
SigInfoCode::Si(SigInfoCodeSi::SI_ASYNCIO) => Some(SigInfoDetails::SigPoll(unsafe {
self.inner().l_sifields.l_sigpoll
})),
SigInfoCode::Si(SigInfoCodeSi::SI_TKILL) => Some(SigInfoDetails::Kill(unsafe {
self.inner().l_sifields.l_kill
})),
SigInfoCode::Cld(_) => Some(SigInfoDetails::SigChld(unsafe {
self.inner().l_sifields.l_sigchld
})),
SigInfoCode::Ill(_) => Some(SigInfoDetails::SigFault(unsafe {
self.inner().l_sifields.l_sigfault
})),
SigInfoCode::Fpe(_) => Some(SigInfoDetails::SigFault(unsafe {
self.inner().l_sifields.l_sigfault
})),
SigInfoCode::Segv(_) => Some(SigInfoDetails::SigFault(unsafe {
self.inner().l_sifields.l_sigfault
})),
SigInfoCode::Bus(_) => Some(SigInfoDetails::SigFault(unsafe {
self.inner().l_sifields.l_sigfault
})),
SigInfoCode::Trap(_) => Some(SigInfoDetails::SigFault(unsafe {
self.inner().l_sifields.l_sigfault
})),
SigInfoCode::Poll(_) => Some(SigInfoDetails::SigFault(unsafe {
self.inner().l_sifields.l_sigfault
})),
SigInfoCode::Sys(_) => Some(SigInfoDetails::SigSys(unsafe {
self.inner().l_sifields.l_sigsys
})),
}
}
unsafe fn new(signal: Signal, errno: i32, code: i32, fields: SigInfoDetailsFields) -> Self {
Self(bindings::linux_siginfo_t {
l__bindgen_anon_1: bindings::linux_siginfo__bindgen_ty_1 {
l__bindgen_anon_1: bindings::linux_siginfo__bindgen_ty_1__bindgen_ty_1 {
lsi_signo: signal.into(),
lsi_errno: errno,
lsi_code: code,
l_sifields: fields,
},
},
})
}
pub fn new_for_kill(signal: Signal, sender_pid: i32, sender_uid: u32) -> Self {
unsafe {
Self::new(
signal,
0,
SigInfoCodeSi::SI_USER.into(),
SigInfoDetailsFields {
l_kill: SigInfoDetailsKill {
l_pid: sender_pid,
l_uid: sender_uid,
},
},
)
}
}
pub fn new_for_tkill(signal: Signal, sender_pid: i32, sender_uid: u32) -> Self {
unsafe {
Self::new(
signal,
0,
SigInfoCodeSi::SI_TKILL.into(),
SigInfoDetailsFields {
l_kill: SigInfoDetailsKill {
l_pid: sender_pid,
l_uid: sender_uid,
},
},
)
}
}
pub fn new_for_timer(signal: Signal, timer_id: i32, overrun: i32) -> Self {
unsafe {
Self::new(
signal,
0,
SigInfoCodeSi::SI_TIMER.into(),
SigInfoDetailsFields {
l_timer: SigInfoDetailsTimer {
l_tid: timer_id,
l_overrun: overrun,
l_sigval: core::mem::zeroed(),
l_sys_private: 0,
},
},
)
}
}
pub fn new_for_mq(
signal: Signal,
sender_pid: i32,
sender_uid: u32,
sigval: linux_sigval,
) -> Self {
unsafe {
Self::new(
signal,
0,
SigInfoCodeSi::SI_MESGQ.into(),
SigInfoDetailsFields {
l_rt: SigInfoDetailsRt {
l_pid: sender_pid,
l_uid: sender_uid,
l_sigval: sigval,
},
},
)
}
}
pub fn new_for_sigchld_exited(
exit_signal: Signal,
child_pid: i32,
child_uid: u32,
child_exit_status: i32,
child_utime: i64,
child_stime: i64,
) -> Self {
unsafe {
Self::new(
exit_signal,
0,
SigInfoCodeCld::CLD_EXITED.into(),
SigInfoDetailsFields {
l_sigchld: SigInfoDetailsSigChld {
l_pid: child_pid,
l_uid: child_uid,
l_status: child_exit_status,
l_utime: child_utime,
l_stime: child_stime,
},
},
)
}
}
fn new_for_sigchld_signaled(
exit_signal: Signal,
code: SigInfoCodeCld,
child_pid: i32,
child_uid: u32,
signal: Signal,
child_utime: i64,
child_stime: i64,
) -> Self {
unsafe {
Self::new(
exit_signal,
0,
code.into(),
SigInfoDetailsFields {
l_sigchld: SigInfoDetailsSigChld {
l_pid: child_pid,
l_uid: child_uid,
l_status: signal.into(),
l_utime: child_utime,
l_stime: child_stime,
},
},
)
}
}
pub fn new_for_sigchld_killed(
exit_signal: Signal,
child_pid: i32,
child_uid: u32,
fatal_signal: Signal,
child_utime: i64,
child_stime: i64,
) -> Self {
Self::new_for_sigchld_signaled(
exit_signal,
SigInfoCodeCld::CLD_KILLED,
child_pid,
child_uid,
fatal_signal,
child_utime,
child_stime,
)
}
pub fn new_for_sigchld_dumped(
exit_signal: Signal,
child_pid: i32,
child_uid: u32,
fatal_signal: Signal,
child_utime: i64,
child_stime: i64,
) -> Self {
Self::new_for_sigchld_signaled(
exit_signal,
SigInfoCodeCld::CLD_DUMPED,
child_pid,
child_uid,
fatal_signal,
child_utime,
child_stime,
)
}
pub fn new_for_sigchld_trapped(
exit_signal: Signal,
child_pid: i32,
child_uid: u32,
child_utime: i64,
child_stime: i64,
) -> Self {
Self::new_for_sigchld_signaled(
exit_signal,
SigInfoCodeCld::CLD_TRAPPED,
child_pid,
child_uid,
Signal::SIGTRAP,
child_utime,
child_stime,
)
}
pub fn new_for_sigchld_stopped(
exit_signal: Signal,
child_pid: i32,
child_uid: u32,
child_utime: i64,
child_stime: i64,
) -> Self {
Self::new_for_sigchld_signaled(
exit_signal,
SigInfoCodeCld::CLD_STOPPED,
child_pid,
child_uid,
Signal::SIGSTOP,
child_utime,
child_stime,
)
}
pub fn new_for_sigchld_continued(
exit_signal: Signal,
child_pid: i32,
child_uid: u32,
child_utime: i64,
child_stime: i64,
) -> Self {
Self::new_for_sigchld_signaled(
exit_signal,
SigInfoCodeCld::CLD_CONTINUED,
child_pid,
child_uid,
Signal::SIGCONT,
child_utime,
child_stime,
)
}
}
impl Default for siginfo_t {
fn default() -> Self {
unsafe { core::mem::zeroed() }
}
}
#[allow(non_camel_case_types)]
pub type linux_sigset_t = bindings::linux_sigset_t;
#[repr(transparent)]
#[derive(Copy, Clone, Eq, PartialEq, Debug, Default, VirtualAddressSpaceIndependent)]
#[allow(non_camel_case_types)]
pub struct sigset_t(linux_sigset_t);
unsafe impl TransparentWrapper<linux_sigset_t> for sigset_t {}
unsafe impl shadow_pod::Pod for sigset_t {}
impl sigset_t {
pub const EMPTY: Self = Self(0);
pub const FULL: Self = Self(!0);
pub fn has(&self, sig: Signal) -> bool {
(*self & sigset_t::from(sig)).0 != 0
}
pub fn lowest(&self) -> Option<Signal> {
if self.0 == 0 {
return None;
}
for i in i32::from(Signal::MIN)..=i32::from(Signal::MAX) {
let s = Signal::try_from(i).unwrap();
if self.has(s) {
return Some(s);
}
}
unreachable!();
}
pub fn is_empty(&self) -> bool {
*self == sigset_t::EMPTY
}
pub fn del(&mut self, sig: Signal) {
*self &= !sigset_t::from(sig);
}
pub fn add(&mut self, sig: Signal) {
*self |= sigset_t::from(sig);
}
}
impl From<Signal> for sigset_t {
#[inline]
fn from(value: Signal) -> Self {
let value = i32::from(value);
debug_assert!(value <= 64);
Self(1 << (value - 1))
}
}
#[test]
fn test_from_signal() {
let sigset = sigset_t::from(Signal::SIGABRT);
assert!(sigset.has(Signal::SIGABRT));
assert!(!sigset.has(Signal::SIGSEGV));
assert_ne!(sigset, sigset_t::EMPTY);
}
impl core::ops::BitOr for sigset_t {
type Output = Self;
fn bitor(self, rhs: Self) -> Self::Output {
Self(self.0 | rhs.0)
}
}
#[test]
fn test_bitor() {
let sigset = sigset_t::from(Signal::SIGABRT) | sigset_t::from(Signal::SIGSEGV);
assert!(sigset.has(Signal::SIGABRT));
assert!(sigset.has(Signal::SIGSEGV));
assert!(!sigset.has(Signal::SIGALRM));
}
impl core::ops::BitOrAssign for sigset_t {
fn bitor_assign(&mut self, rhs: Self) {
self.0 |= rhs.0
}
}
#[test]
fn test_bitorassign() {
let mut sigset = sigset_t::from(Signal::SIGABRT);
sigset |= sigset_t::from(Signal::SIGSEGV);
assert!(sigset.has(Signal::SIGABRT));
assert!(sigset.has(Signal::SIGSEGV));
assert!(!sigset.has(Signal::SIGALRM));
}
impl core::ops::BitAnd for sigset_t {
type Output = Self;
fn bitand(self, rhs: Self) -> Self::Output {
Self(self.0 & rhs.0)
}
}
#[test]
fn test_bitand() {
let lhs = sigset_t::from(Signal::SIGABRT) | sigset_t::from(Signal::SIGSEGV);
let rhs = sigset_t::from(Signal::SIGABRT) | sigset_t::from(Signal::SIGALRM);
let and = lhs & rhs;
assert!(and.has(Signal::SIGABRT));
assert!(!and.has(Signal::SIGSEGV));
assert!(!and.has(Signal::SIGALRM));
}
impl core::ops::BitAndAssign for sigset_t {
fn bitand_assign(&mut self, rhs: Self) {
self.0 &= rhs.0
}
}
#[test]
fn test_bitand_assign() {
let mut set = sigset_t::from(Signal::SIGABRT) | sigset_t::from(Signal::SIGSEGV);
set &= sigset_t::from(Signal::SIGABRT) | sigset_t::from(Signal::SIGALRM);
assert!(set.has(Signal::SIGABRT));
assert!(!set.has(Signal::SIGSEGV));
assert!(!set.has(Signal::SIGALRM));
}
impl core::ops::Not for sigset_t {
type Output = Self;
fn not(self) -> Self::Output {
Self(!self.0)
}
}
#[test]
fn test_not() {
let set = sigset_t::from(Signal::SIGABRT) | sigset_t::from(Signal::SIGSEGV);
let set = !set;
assert!(!set.has(Signal::SIGABRT));
assert!(!set.has(Signal::SIGSEGV));
assert!(set.has(Signal::SIGALRM));
}
pub type SignalHandlerFn = unsafe extern "C" fn(i32);
pub type SignalActionFn = unsafe extern "C" fn(i32, *mut siginfo_t, *mut core::ffi::c_void);
pub enum SignalHandler {
Handler(SignalHandlerFn),
Action(SignalActionFn),
SigIgn,
SigDfl,
}
#[allow(non_camel_case_types)]
pub type linux_sigaction = bindings::linux_sigaction;
#[cfg(target_arch = "x86_64")]
#[naked_function::naked]
pub unsafe extern "C" fn sigaction_restorer() {
asm!("mov rax, 15", "syscall", "ud2")
}
static_assertions::const_assert_eq!(bindings::LINUX___NR_rt_sigreturn, 15);
#[derive(Copy, Clone)]
#[repr(C)]
#[allow(non_camel_case_types)]
pub struct sigaction(linux_sigaction);
unsafe impl shadow_pod::Pod for sigaction {}
impl sigaction {
const SIG_DFL: usize = 0;
const SIG_IGN: usize = 1;
pub fn new_raw(
handler: SignalHandler,
flags: SigActionFlags,
mask: sigset_t,
restorer: Option<unsafe extern "C" fn()>,
) -> Self {
let handler = match handler {
SignalHandler::Handler(h) => {
assert!(!flags.contains(SigActionFlags::SA_SIGINFO));
Some(h)
}
SignalHandler::Action(a) => {
assert!(flags.contains(SigActionFlags::SA_SIGINFO));
Some(unsafe { core::mem::transmute::<SignalActionFn, SignalHandlerFn>(a) })
}
SignalHandler::SigIgn => {
assert!(!flags.contains(SigActionFlags::SA_SIGINFO));
Some(unsafe { core::mem::transmute::<usize, SignalHandlerFn>(Self::SIG_IGN) })
}
SignalHandler::SigDfl => {
assert!(!flags.contains(SigActionFlags::SA_SIGINFO));
static_assertions::const_assert_eq!(sigaction::SIG_DFL, 0);
None
}
};
sigaction(linux_sigaction {
lsa_handler: handler,
lsa_flags: flags.bits(),
lsa_mask: mask.0,
lsa_restorer: restorer,
})
}
pub fn new_with_default_restorer(
handler: SignalHandler,
flags: SigActionFlags,
mask: sigset_t,
) -> Self {
Self::new_raw(
handler,
flags | SigActionFlags::SA_RESTORER,
mask,
Some(sigaction_restorer),
)
}
pub fn wrap(si: linux_sigaction) -> Self {
Self(si)
}
pub fn wrap_ref(si: &linux_sigaction) -> &Self {
unsafe { &*(core::ptr::from_ref(si) as *const Self) }
}
pub fn wrap_mut(si: &mut linux_sigaction) -> &mut Self {
unsafe { &mut *(core::ptr::from_mut(si) as *mut Self) }
}
pub unsafe fn peel(si: Self) -> linux_sigaction {
si.0
}
pub fn flags(&self) -> Option<SigActionFlags> {
SigActionFlags::from_bits(self.0.lsa_flags)
}
pub fn flags_retain(&self) -> SigActionFlags {
SigActionFlags::from_bits_retain(self.0.lsa_flags)
}
pub fn mask(&self) -> sigset_t {
sigset_t::wrap(self.0.lsa_mask)
}
pub unsafe fn handler(&self) -> SignalHandler {
let as_usize = self.as_usize();
if as_usize == Self::SIG_IGN {
SignalHandler::SigIgn
} else if as_usize == Self::SIG_DFL {
SignalHandler::SigDfl
} else if self.flags_retain().contains(SigActionFlags::SA_SIGINFO) {
let handler_fn: SignalHandlerFn = self.0.lsa_handler.unwrap();
let action_fn: SignalActionFn =
unsafe { core::mem::transmute::<SignalHandlerFn, SignalActionFn>(handler_fn) };
SignalHandler::Action(action_fn)
} else {
SignalHandler::Handler(self.0.lsa_handler.unwrap())
}
}
fn as_usize(&self) -> usize {
self.0.lsa_handler.map(|f| f as usize).unwrap_or(0)
}
pub fn is_ignore(&self) -> bool {
self.as_usize() == Self::SIG_IGN
}
pub fn is_default(&self) -> bool {
self.as_usize() == Self::SIG_DFL
}
}
impl Default for sigaction {
fn default() -> Self {
unsafe { core::mem::zeroed() }
}
}
#[derive(Eq, PartialEq, Debug)]
#[repr(C)]
pub enum LinuxDefaultAction {
TERM,
IGN,
CORE,
STOP,
CONT,
}
pub fn defaultaction(sig: Signal) -> LinuxDefaultAction {
use LinuxDefaultAction as Action;
match sig {
Signal::SIGCONT => Action::CONT,
Signal::SIGABRT
| Signal::SIGBUS
| Signal::SIGFPE
| Signal::SIGILL
| Signal::SIGQUIT
| Signal::SIGSEGV
| Signal::SIGSYS
| Signal::SIGTRAP
| Signal::SIGXCPU
| Signal::SIGXFSZ => Action::CORE,
Signal::SIGCHLD
| Signal::SIGURG
| Signal::SIGWINCH => Action::IGN,
Signal::SIGSTOP
| Signal::SIGTSTP
| Signal::SIGTTIN
| Signal::SIGTTOU => Action::STOP,
Signal::SIGALRM
| Signal::SIGHUP
| Signal::SIGINT
| Signal::SIGIO
| Signal::SIGKILL
| Signal::SIGPIPE
| Signal::SIGPROF
| Signal::SIGPWR
| Signal::SIGSTKFLT
| Signal::SIGTERM
| Signal::SIGUSR1
| Signal::SIGUSR2
| Signal::SIGVTALRM => Action::TERM,
other => {
assert!(other.is_realtime());
Action::TERM
},
}
}
pub fn kill_raw(pid: kernel_pid_t, sig: i32) -> Result<(), Errno> {
unsafe { syscall!(linux_syscall::SYS_kill, pid, sig) }
.check()
.map_err(Errno::from)
}
pub fn kill_process(pid: Pid, sig: Option<Signal>) -> Result<(), Errno> {
kill_raw(pid.as_raw_nonzero().into(), Signal::as_raw(sig))
}
pub fn kill_process_group(pid: Pid, sig: Option<Signal>) -> Result<(), Errno> {
kill_raw(-i32::from(pid.as_raw_nonzero()), Signal::as_raw(sig))
}
pub fn kill_current_process_group(sig: Option<Signal>) -> Result<(), Errno> {
kill_raw(0, Signal::as_raw(sig))
}
pub unsafe fn rt_sigaction_raw(
signo: i32,
new_action: *const sigaction,
old_action: *mut sigaction,
sigsetsize: usize,
) -> Result<(), Errno> {
unsafe {
syscall!(
linux_syscall::SYS_rt_sigaction,
signo,
new_action,
old_action,
sigsetsize
)
}
.check()
.map_err(Errno::from)
}
pub unsafe fn rt_sigaction(
signal: Signal,
new_action: &sigaction,
old_action: Option<&mut sigaction>,
) -> Result<(), Errno> {
unsafe {
rt_sigaction_raw(
signal.as_i32(),
new_action,
old_action
.map(core::ptr::from_mut)
.unwrap_or(core::ptr::null_mut()),
core::mem::size_of::<sigset_t>(),
)
}
}
#[allow(non_camel_case_types)]
#[repr(i32)]
#[derive(Debug, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)]
pub enum SigProcMaskAction {
SIG_BLOCK = const_conversions::i32_from_u32(bindings::LINUX_SIG_BLOCK),
SIG_UNBLOCK = const_conversions::i32_from_u32(bindings::LINUX_SIG_UNBLOCK),
SIG_SETMASK = const_conversions::i32_from_u32(bindings::LINUX_SIG_SETMASK),
}
pub unsafe fn rt_sigprocmask_raw(
how: i32,
sigset_in: *const sigset_t,
sigset_out: *mut sigset_t,
sigset_sz: usize,
) -> Result<(), Errno> {
unsafe {
syscall!(
linux_syscall::SYS_rt_sigprocmask,
how,
sigset_in,
sigset_out,
sigset_sz,
)
.check()
.map_err(Errno::from)
}
}
pub fn rt_sigprocmask(
how: SigProcMaskAction,
sigset_in: &sigset_t,
sigset_out: Option<&mut sigset_t>,
) -> Result<(), Errno> {
unsafe {
rt_sigprocmask_raw(
how.into(),
sigset_in,
sigset_out
.map(core::ptr::from_mut)
.unwrap_or(core::ptr::null_mut()),
core::mem::size_of::<sigset_t>(),
)
}
}
#[cfg(test)]
mod rt_sigaction_tests {
use core::sync::atomic::AtomicI32;
use shadow_pod::zeroed;
use super::*;
#[cfg(not(miri))]
#[test]
fn test_rt_sigaction() {
static CALL_COUNTER: AtomicI32 = AtomicI32::new(0);
extern "C" fn handler(_signo: i32) {
CALL_COUNTER.fetch_add(1, core::sync::atomic::Ordering::Relaxed);
}
let action = sigaction::new_with_default_restorer(
SignalHandler::Handler(handler),
SigActionFlags::empty(),
sigset_t::EMPTY,
);
let signal = Signal::SIGUSR2;
let mut old_action = zeroed();
unsafe { rt_sigaction(signal, &action, Some(&mut old_action)) }.unwrap();
let mut old_mask: sigset_t = sigset_t::EMPTY;
let mask = sigset_t::from(signal);
rt_sigprocmask(SigProcMaskAction::SIG_UNBLOCK, &mask, Some(&mut old_mask)).unwrap();
let pid = rustix::process::getpid();
let tid = rustix::thread::gettid();
unsafe {
linux_syscall::syscall!(
linux_syscall::SYS_tgkill,
pid.as_raw_nonzero().get(),
tid.as_raw_nonzero().get(),
signal.as_i32()
)
}
.check()
.unwrap();
assert_eq!(CALL_COUNTER.load(core::sync::atomic::Ordering::Relaxed), 1);
rt_sigprocmask(SigProcMaskAction::SIG_SETMASK, &old_mask, None).unwrap();
unsafe { rt_sigaction(signal, &old_action, None) }.unwrap();
}
}
pub use bindings::linux_stack_t;
#[allow(non_camel_case_types)]
pub type stack_t = linux_stack_t;
impl stack_t {
pub fn new(sp: *mut core::ffi::c_void, flags: SigAltStackFlags, size: usize) -> Self {
Self {
ss_sp: sp,
ss_flags: flags.bits(),
ss_size: size.try_into().unwrap(),
}
}
pub fn flags_retain(&self) -> SigAltStackFlags {
SigAltStackFlags::from_bits_retain(self.ss_flags)
}
pub fn sp(&self) -> *mut core::ffi::c_void {
self.ss_sp
}
pub fn size(&self) -> usize {
self.ss_size.try_into().unwrap()
}
}
pub const LINUX_SS_AUTODISARM: u32 = 1 << 31;
bitflags::bitflags! {
#[repr(transparent)]
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
pub struct SigAltStackFlags: i32 {
const SS_AUTODISARM = i32_from_u32_allowing_wraparound(LINUX_SS_AUTODISARM);
const SS_ONSTACK = const_conversions::i32_from_u32(bindings::LINUX_SS_ONSTACK);
const SS_DISABLE= const_conversions::i32_from_u32(bindings::LINUX_SS_DISABLE);
}
}
unsafe impl VirtualAddressSpaceIndependent for SigAltStackFlags {}
pub unsafe fn sigaltstack_raw(
new_stack: *const stack_t,
old_stack: *mut stack_t,
) -> Result<(), Errno> {
unsafe { syscall!(linux_syscall::SYS_sigaltstack, new_stack, old_stack) }
.check()
.map_err(Errno::from)
}
pub unsafe fn sigaltstack(
new_stack: Option<&stack_t>,
old_stack: Option<&mut stack_t>,
) -> Result<(), Errno> {
unsafe {
sigaltstack_raw(
new_stack
.map(core::ptr::from_ref)
.unwrap_or(core::ptr::null()),
old_stack
.map(core::ptr::from_mut)
.unwrap_or(core::ptr::null_mut()),
)
}
}
pub fn tgkill_raw(tgid: kernel_pid_t, tid: kernel_pid_t, signo: i32) -> Result<(), Errno> {
unsafe { syscall!(linux_syscall::SYS_tgkill, tgid, tid, signo) }
.check()
.map_err(Errno::from)
}
pub fn tgkill(tgid: Pid, tid: Pid, signal: Option<Signal>) -> Result<(), Errno> {
tgkill_raw(
Pid::as_raw(Some(tgid)),
Pid::as_raw(Some(tid)),
signal.map(i32::from).unwrap_or(0),
)
}
mod export {
use crate::bindings::{linux_siginfo_t, linux_sigset_t};
use super::*;
#[no_mangle]
pub extern "C-unwind" fn linux_signal_is_valid(signo: i32) -> bool {
Signal::try_from(signo).is_ok()
}
#[no_mangle]
pub extern "C-unwind" fn linux_signal_is_realtime(signo: i32) -> bool {
let Ok(signal) = Signal::try_from(signo) else {
return false;
};
signal.is_realtime()
}
#[no_mangle]
pub extern "C-unwind" fn linux_sigemptyset() -> linux_sigset_t {
sigset_t::EMPTY.0
}
#[no_mangle]
pub extern "C-unwind" fn linux_sigfullset() -> linux_sigset_t {
sigset_t::FULL.0
}
#[no_mangle]
pub unsafe extern "C-unwind" fn linux_sigaddset(set: *mut linux_sigset_t, signo: i32) {
let set = sigset_t::wrap_mut(unsafe { set.as_mut().unwrap() });
let signo = Signal::try_from(signo).unwrap();
set.add(signo);
}
#[no_mangle]
pub unsafe extern "C-unwind" fn linux_sigdelset(set: *mut linux_sigset_t, signo: i32) {
let set = sigset_t::wrap_mut(unsafe { set.as_mut().unwrap() });
let signo = Signal::try_from(signo).unwrap();
set.del(signo);
}
#[no_mangle]
pub unsafe extern "C-unwind" fn linux_sigismember(
set: *const linux_sigset_t,
signo: i32,
) -> bool {
let set = sigset_t::wrap_ref(unsafe { set.as_ref().unwrap() });
set.has(signo.try_into().unwrap())
}
#[no_mangle]
pub unsafe extern "C-unwind" fn linux_sigisemptyset(set: *const linux_sigset_t) -> bool {
let set = sigset_t::wrap_ref(unsafe { set.as_ref().unwrap() });
set.is_empty()
}
#[no_mangle]
pub unsafe extern "C-unwind" fn linux_sigorset(
lhs: *const linux_sigset_t,
rhs: *const linux_sigset_t,
) -> linux_sigset_t {
let lhs = unsafe { lhs.as_ref().unwrap() };
let rhs = unsafe { rhs.as_ref().unwrap() };
sigset_t(*lhs | *rhs).0
}
#[no_mangle]
pub unsafe extern "C-unwind" fn linux_sigandset(
lhs: *const linux_sigset_t,
rhs: *const linux_sigset_t,
) -> linux_sigset_t {
let lhs = unsafe { lhs.as_ref().unwrap() };
let rhs = unsafe { rhs.as_ref().unwrap() };
sigset_t(*lhs & *rhs).0
}
#[no_mangle]
pub unsafe extern "C-unwind" fn linux_signotset(set: *const linux_sigset_t) -> linux_sigset_t {
let set = unsafe { set.as_ref().unwrap() };
sigset_t(!*set).0
}
#[no_mangle]
pub unsafe extern "C-unwind" fn linux_siglowest(set: *const linux_sigset_t) -> i32 {
let set = sigset_t::wrap_ref(unsafe { set.as_ref().unwrap() });
match set.lowest() {
Some(s) => s.into(),
None => 0,
}
}
#[no_mangle]
pub extern "C-unwind" fn linux_defaultAction(signo: i32) -> LinuxDefaultAction {
let sig = Signal::try_from(signo).unwrap();
defaultaction(sig)
}
#[no_mangle]
pub unsafe extern "C-unwind" fn linux_kill(pid: i32, sig: i32) -> i32 {
match kill_raw(pid, sig) {
Ok(()) => 0,
Err(e) => e.to_negated_i32(),
}
}
#[no_mangle]
pub unsafe extern "C-unwind" fn linux_sigaction_handler(
sa: *const linux_sigaction,
) -> Option<unsafe extern "C" fn(i32)> {
let sa = sigaction::wrap_ref(unsafe { sa.as_ref().unwrap() });
match unsafe { sa.handler() } {
SignalHandler::Handler(h) => Some(h),
_ => None,
}
}
#[no_mangle]
pub unsafe extern "C-unwind" fn linux_sigaction_action(
sa: *const linux_sigaction,
) -> Option<unsafe extern "C" fn(i32, *mut linux_siginfo_t, *mut core::ffi::c_void)> {
let sa = sigaction::wrap_ref(unsafe { sa.as_ref().unwrap() });
match unsafe { sa.handler() } {
SignalHandler::Action(h) =>
{
Some(unsafe {
core::mem::transmute::<
unsafe extern "C" fn(i32, *mut siginfo_t, *mut core::ffi::c_void),
unsafe extern "C" fn(i32, *mut linux_siginfo_t, *mut core::ffi::c_void),
>(h)
})
}
_ => None,
}
}
#[no_mangle]
pub unsafe extern "C-unwind" fn linux_sigaction_is_ign(sa: *const linux_sigaction) -> bool {
let sa = sigaction::wrap_ref(unsafe { sa.as_ref().unwrap() });
matches!(unsafe { sa.handler() }, SignalHandler::SigIgn)
}
#[no_mangle]
pub unsafe extern "C-unwind" fn linux_sigaction_is_dfl(sa: *const linux_sigaction) -> bool {
let sa = sigaction::wrap_ref(unsafe { sa.as_ref().unwrap() });
matches!(unsafe { sa.handler() }, SignalHandler::SigDfl)
}
}