use serde::Deserialize;
use serde::Serialize;
use crate::Pid;
use crate::Tid;
use crate::error::Errno;
pub const SIGNAL_INFO_SIZE: usize = 128;
#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub enum ChildExitSignalDisposition {
Ignored,
PendingBlocked,
PendingEligible,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub enum ChildExitSignalErrorKind {
Unsupported,
Invalid,
Backend,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub enum ChildExitSignalOutcome {
Accepted {
disposition: ChildExitSignalDisposition,
pending_generation: u64,
coalesced: bool,
},
RejectedBeforeCommit {
kind: ChildExitSignalErrorKind,
errno: Errno,
},
FailedAfterCommit {
errno: Errno,
pending_generation: u64,
},
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub enum ProcessAlarmSignalDisposition {
Ignored,
Caught,
DefaultFatal,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct ProcessAlarmSignalReceipt {
pub blocked: bool,
pub disposition: ProcessAlarmSignalDisposition,
pub pending_generation: u64,
pub coalesced: bool,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub enum ProcessAlarmSignalErrorKind {
Unsupported,
Invalid,
Backend,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub enum ProcessAlarmSignalOutcome {
Accepted(ProcessAlarmSignalReceipt),
RejectedBeforeCommit {
kind: ProcessAlarmSignalErrorKind,
errno: Errno,
},
FailedAfterCommit {
errno: Errno,
receipt: ProcessAlarmSignalReceipt,
},
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub enum SignalTarget {
Process {
pid: Pid,
},
Thread {
pid: Pid,
tid: Tid,
},
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
#[serde(try_from = "SignalEventWire", into = "SignalEventWire")]
pub struct SignalEvent {
signal: u8,
siginfo: [u8; SIGNAL_INFO_SIZE],
target: SignalTarget,
}
#[derive(Serialize, Deserialize)]
struct SignalEventWire {
signal: i32,
siginfo: Vec<u8>,
target: SignalTarget,
}
impl From<SignalEvent> for SignalEventWire {
fn from(event: SignalEvent) -> Self {
Self {
signal: event.signal(),
siginfo: event.siginfo().to_vec(),
target: event.target(),
}
}
}
impl TryFrom<SignalEventWire> for SignalEvent {
type Error = Errno;
fn try_from(wire: SignalEventWire) -> Result<Self, Self::Error> {
let info = wire.siginfo.try_into().map_err(|_| Errno::EINVAL)?;
Self::new(wire.signal, info, wire.target)
}
}
impl SignalEvent {
pub fn new(
signal: i32,
siginfo: [u8; SIGNAL_INFO_SIZE],
target: SignalTarget,
) -> Result<Self, Errno> {
if !(1..=64).contains(&signal)
|| i32::from_ne_bytes(siginfo[0..4].try_into().expect("siginfo signo bytes")) != signal
{
return Err(Errno::EINVAL);
}
Ok(Self {
signal: signal as u8,
siginfo,
target,
})
}
pub const fn signal(self) -> i32 {
self.signal as i32
}
pub const fn siginfo(self) -> [u8; SIGNAL_INFO_SIZE] {
self.siginfo
}
pub const fn target(self) -> SignalTarget {
self.target
}
}
#[cfg(test)]
mod tests {
use super::*;
fn siginfo(signal: i32) -> [u8; SIGNAL_INFO_SIZE] {
let mut info = [0; SIGNAL_INFO_SIZE];
info[0..4].copy_from_slice(&signal.to_ne_bytes());
info
}
#[test]
fn signal_event_preserves_raw_realtime_number_payload_and_target() {
let mut info = siginfo(64);
for (index, byte) in info[4..].iter_mut().enumerate() {
*byte = index as u8;
}
let target = SignalTarget::Thread {
pid: Pid::from_raw(41),
tid: Pid::from_raw(42),
};
let event = SignalEvent::new(64, info, target).unwrap();
assert_eq!(event.signal(), 64);
assert_eq!(event.siginfo(), info);
assert_eq!(event.target(), target);
}
#[test]
fn signal_event_rejects_invalid_or_incoherent_numbers() {
let target = SignalTarget::Process {
pid: Pid::from_raw(7),
};
for signal in [i32::MIN, -1, 0, 65, i32::MAX] {
assert_eq!(
SignalEvent::new(signal, siginfo(libc::SIGUSR1), target),
Err(Errno::EINVAL),
"accepted invalid signal {signal}",
);
}
assert_eq!(
SignalEvent::new(libc::SIGUSR2, siginfo(libc::SIGUSR1), target),
Err(Errno::EINVAL),
"accepted an event whose signal and siginfo.si_signo disagree",
);
}
}