#[cfg(doc)]
use super::Concurrent;
use super::{Pid, Result};
pub use crate::signal::{Name, Number, RawNumber};
use std::borrow::Cow;
use std::fmt::Debug;
use std::num::NonZero;
use std::ops::RangeInclusive;
use std::rc::Rc;
pub trait Signals {
const SIGABRT: Number;
const SIGALRM: Number;
const SIGBUS: Number;
const SIGCHLD: Number;
const SIGCLD: Option<Number>;
const SIGCONT: Number;
const SIGEMT: Option<Number>;
const SIGFPE: Number;
const SIGHUP: Number;
const SIGILL: Number;
const SIGINFO: Option<Number>;
const SIGINT: Number;
const SIGIO: Option<Number>;
const SIGIOT: Number;
const SIGKILL: Number;
const SIGLOST: Option<Number>;
const SIGPIPE: Number;
const SIGPOLL: Option<Number>;
const SIGPROF: Number;
const SIGPWR: Option<Number>;
const SIGQUIT: Number;
const SIGSEGV: Number;
const SIGSTKFLT: Option<Number>;
const SIGSTOP: Number;
const SIGSYS: Number;
const SIGTERM: Number;
const SIGTHR: Option<Number>;
const SIGTRAP: Number;
const SIGTSTP: Number;
const SIGTTIN: Number;
const SIGTTOU: Number;
const SIGURG: Number;
const SIGUSR1: Number;
const SIGUSR2: Number;
const SIGVTALRM: Number;
const SIGWINCH: Number;
const SIGXCPU: Number;
const SIGXFSZ: Number;
#[must_use]
fn sigrt_range(&self) -> Option<RangeInclusive<Number>>;
const NAMED_SIGNALS: &'static [(&'static str, Option<Number>)] = &[
("ABRT", Some(Self::SIGABRT)),
("ALRM", Some(Self::SIGALRM)),
("BUS", Some(Self::SIGBUS)),
("CHLD", Some(Self::SIGCHLD)),
("CLD", Self::SIGCLD),
("CONT", Some(Self::SIGCONT)),
("EMT", Self::SIGEMT),
("FPE", Some(Self::SIGFPE)),
("HUP", Some(Self::SIGHUP)),
("ILL", Some(Self::SIGILL)),
("INFO", Self::SIGINFO),
("INT", Some(Self::SIGINT)),
("IO", Self::SIGIO),
("IOT", Some(Self::SIGIOT)),
("KILL", Some(Self::SIGKILL)),
("LOST", Self::SIGLOST),
("PIPE", Some(Self::SIGPIPE)),
("POLL", Self::SIGPOLL),
("PROF", Some(Self::SIGPROF)),
("PWR", Self::SIGPWR),
("QUIT", Some(Self::SIGQUIT)),
("SEGV", Some(Self::SIGSEGV)),
("STKFLT", Self::SIGSTKFLT),
("STOP", Some(Self::SIGSTOP)),
("SYS", Some(Self::SIGSYS)),
("TERM", Some(Self::SIGTERM)),
("THR", Self::SIGTHR),
("TRAP", Some(Self::SIGTRAP)),
("TSTP", Some(Self::SIGTSTP)),
("TTIN", Some(Self::SIGTTIN)),
("TTOU", Some(Self::SIGTTOU)),
("URG", Some(Self::SIGURG)),
("USR1", Some(Self::SIGUSR1)),
("USR2", Some(Self::SIGUSR2)),
("VTALRM", Some(Self::SIGVTALRM)),
("WINCH", Some(Self::SIGWINCH)),
("XCPU", Some(Self::SIGXCPU)),
("XFSZ", Some(Self::SIGXFSZ)),
];
fn iter_sigrt(&self) -> impl DoubleEndedIterator<Item = Number> + use<Self> {
let range = match self.sigrt_range() {
Some(range) => range.start().as_raw()..=range.end().as_raw(),
#[allow(clippy::reversed_empty_ranges, reason = "false positive")]
None => 0..=-1,
};
range.filter_map(|raw| NonZero::new(raw).map(Number::from_raw_unchecked))
}
#[must_use]
fn to_signal_number<N: Into<RawNumber>>(&self, number: N) -> Option<Number> {
fn inner<S: Signals + ?Sized>(system: &S, raw_number: RawNumber) -> Option<Number> {
let non_zero = NonZero::new(raw_number)?;
let number = Number::from_raw_unchecked(non_zero);
(S::NAMED_SIGNALS
.iter()
.any(|signal| signal.1 == Some(number))
|| system
.sigrt_range()
.is_some_and(|range| range.contains(&number)))
.then_some(number)
}
inner(self, number.into())
}
#[must_use]
fn sig2str<N: Into<RawNumber>>(&self, signal: N) -> Option<Cow<'static, str>> {
fn inner<S: Signals + ?Sized>(
system: &S,
raw_number: RawNumber,
) -> Option<Cow<'static, str>> {
let number = Number::from_raw_unchecked(NonZero::new(raw_number)?);
match () {
() if number == S::SIGABRT => Some(Cow::Borrowed("ABRT")),
() if number == S::SIGALRM => Some(Cow::Borrowed("ALRM")),
() if number == S::SIGBUS => Some(Cow::Borrowed("BUS")),
() if number == S::SIGCHLD => Some(Cow::Borrowed("CHLD")),
() if number == S::SIGCONT => Some(Cow::Borrowed("CONT")),
() if number == S::SIGFPE => Some(Cow::Borrowed("FPE")),
() if number == S::SIGHUP => Some(Cow::Borrowed("HUP")),
() if number == S::SIGILL => Some(Cow::Borrowed("ILL")),
() if number == S::SIGINT => Some(Cow::Borrowed("INT")),
() if number == S::SIGKILL => Some(Cow::Borrowed("KILL")),
() if number == S::SIGPIPE => Some(Cow::Borrowed("PIPE")),
() if number == S::SIGQUIT => Some(Cow::Borrowed("QUIT")),
() if number == S::SIGSEGV => Some(Cow::Borrowed("SEGV")),
() if number == S::SIGSTOP => Some(Cow::Borrowed("STOP")),
() if number == S::SIGTERM => Some(Cow::Borrowed("TERM")),
() if number == S::SIGTSTP => Some(Cow::Borrowed("TSTP")),
() if number == S::SIGTTIN => Some(Cow::Borrowed("TTIN")),
() if number == S::SIGTTOU => Some(Cow::Borrowed("TTOU")),
() if number == S::SIGUSR1 => Some(Cow::Borrowed("USR1")),
() if number == S::SIGUSR2 => Some(Cow::Borrowed("USR2")),
() if Some(number) == S::SIGPOLL => Some(Cow::Borrowed("POLL")),
() if number == S::SIGPROF => Some(Cow::Borrowed("PROF")),
() if number == S::SIGSYS => Some(Cow::Borrowed("SYS")),
() if number == S::SIGTRAP => Some(Cow::Borrowed("TRAP")),
() if number == S::SIGURG => Some(Cow::Borrowed("URG")),
() if number == S::SIGVTALRM => Some(Cow::Borrowed("VTALRM")),
() if number == S::SIGWINCH => Some(Cow::Borrowed("WINCH")),
() if number == S::SIGXCPU => Some(Cow::Borrowed("XCPU")),
() if number == S::SIGXFSZ => Some(Cow::Borrowed("XFSZ")),
() if Some(number) == S::SIGEMT => Some(Cow::Borrowed("EMT")),
() if Some(number) == S::SIGINFO => Some(Cow::Borrowed("INFO")),
() if Some(number) == S::SIGIO => Some(Cow::Borrowed("IO")),
() if Some(number) == S::SIGLOST => Some(Cow::Borrowed("LOST")),
() if Some(number) == S::SIGPWR => Some(Cow::Borrowed("PWR")),
() if Some(number) == S::SIGSTKFLT => Some(Cow::Borrowed("STKFLT")),
() if Some(number) == S::SIGTHR => Some(Cow::Borrowed("THR")),
_ => {
let range = system.sigrt_range()?;
if number == *range.start() {
Some(Cow::Borrowed("RTMIN"))
} else if number == *range.end() {
Some(Cow::Borrowed("RTMAX"))
} else if range.contains(&number) {
let rtmin = range.start().as_raw();
let rtmax = range.end().as_raw();
if raw_number <= rtmin.midpoint(rtmax) {
let offset = raw_number - rtmin;
Some(Cow::Owned(format!("RTMIN+{}", offset)))
} else {
let offset = rtmax - raw_number;
Some(Cow::Owned(format!("RTMAX-{}", offset)))
}
} else {
None
}
}
}
}
inner(self, signal.into())
}
#[must_use]
fn str2sig(&self, name: &str) -> Option<Number> {
if let Ok(index) = Self::NAMED_SIGNALS.binary_search_by_key(&name, |s| s.0) {
return Self::NAMED_SIGNALS[index].1;
}
enum BaseName {
Rtmin,
Rtmax,
}
let (basename, suffix) = if let Some(suffix) = name.strip_prefix("RTMIN") {
(BaseName::Rtmin, suffix)
} else if let Some(suffix) = name.strip_prefix("RTMAX") {
(BaseName::Rtmax, suffix)
} else {
return None;
};
if !suffix.is_empty() && !suffix.starts_with(['+', '-']) {
return None;
}
let range = self.sigrt_range()?;
let base_raw = match basename {
BaseName::Rtmin => range.start().as_raw(),
BaseName::Rtmax => range.end().as_raw(),
};
let raw_number = if suffix.is_empty() {
base_raw
} else {
let offset: RawNumber = suffix.parse().ok()?;
base_raw.checked_add(offset)?
};
let number = Number::from_raw_unchecked(NonZero::new(raw_number)?);
range.contains(&number).then_some(number)
}
#[must_use]
fn validate_signal(&self, number: RawNumber) -> Option<(Name, Number)> {
let number = Number::from_raw_unchecked(NonZero::new(number)?);
let str_name = self.sig2str(number)?;
Some((str_name.parse().ok()?, number))
}
#[must_use]
fn signal_name_from_number(&self, number: Number) -> Name {
self.validate_signal(number.as_raw()).unwrap().0
}
#[must_use]
fn signal_number_from_name(&self, name: Name) -> Option<Number> {
self.str2sig(&name.as_string())
}
}
impl<S: Signals> Signals for Rc<S> {
const SIGABRT: Number = S::SIGABRT;
const SIGALRM: Number = S::SIGALRM;
const SIGBUS: Number = S::SIGBUS;
const SIGCHLD: Number = S::SIGCHLD;
const SIGCLD: Option<Number> = S::SIGCLD;
const SIGCONT: Number = S::SIGCONT;
const SIGEMT: Option<Number> = S::SIGEMT;
const SIGFPE: Number = S::SIGFPE;
const SIGHUP: Number = S::SIGHUP;
const SIGILL: Number = S::SIGILL;
const SIGINFO: Option<Number> = S::SIGINFO;
const SIGINT: Number = S::SIGINT;
const SIGIO: Option<Number> = S::SIGIO;
const SIGIOT: Number = S::SIGIOT;
const SIGKILL: Number = S::SIGKILL;
const SIGLOST: Option<Number> = S::SIGLOST;
const SIGPIPE: Number = S::SIGPIPE;
const SIGPOLL: Option<Number> = S::SIGPOLL;
const SIGPROF: Number = S::SIGPROF;
const SIGPWR: Option<Number> = S::SIGPWR;
const SIGQUIT: Number = S::SIGQUIT;
const SIGSEGV: Number = S::SIGSEGV;
const SIGSTKFLT: Option<Number> = S::SIGSTKFLT;
const SIGSTOP: Number = S::SIGSTOP;
const SIGSYS: Number = S::SIGSYS;
const SIGTERM: Number = S::SIGTERM;
const SIGTHR: Option<Number> = S::SIGTHR;
const SIGTRAP: Number = S::SIGTRAP;
const SIGTSTP: Number = S::SIGTSTP;
const SIGTTIN: Number = S::SIGTTIN;
const SIGTTOU: Number = S::SIGTTOU;
const SIGURG: Number = S::SIGURG;
const SIGUSR1: Number = S::SIGUSR1;
const SIGUSR2: Number = S::SIGUSR2;
const SIGVTALRM: Number = S::SIGVTALRM;
const SIGWINCH: Number = S::SIGWINCH;
const SIGXCPU: Number = S::SIGXCPU;
const SIGXFSZ: Number = S::SIGXFSZ;
#[inline]
fn sigrt_range(&self) -> Option<RangeInclusive<Number>> {
(self as &S).sigrt_range()
}
const NAMED_SIGNALS: &'static [(&'static str, Option<Number>)] = S::NAMED_SIGNALS;
#[inline]
fn iter_sigrt(&self) -> impl DoubleEndedIterator<Item = Number> + use<S> {
(self as &S).iter_sigrt()
}
#[inline]
fn to_signal_number<N: Into<RawNumber>>(&self, number: N) -> Option<Number> {
(self as &S).to_signal_number(number)
}
#[inline]
fn sig2str<N: Into<RawNumber>>(&self, signal: N) -> Option<Cow<'static, str>> {
(self as &S).sig2str(signal)
}
#[inline]
fn str2sig(&self, name: &str) -> Option<Number> {
(self as &S).str2sig(name)
}
#[inline]
fn validate_signal(&self, number: RawNumber) -> Option<(Name, Number)> {
(self as &S).validate_signal(number)
}
#[inline]
fn signal_name_from_number(&self, number: Number) -> Name {
(self as &S).signal_name_from_number(number)
}
#[inline]
fn signal_number_from_name(&self, name: Name) -> Option<Number> {
(self as &S).signal_number_from_name(name)
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[non_exhaustive]
pub enum SigmaskOp {
Add,
Remove,
Set,
}
pub trait Sigset: Clone + Default + 'static {
#[inline(always)]
#[must_use]
fn new() -> Self {
Default::default()
}
#[must_use]
fn full() -> Self;
fn insert(&mut self, signal: Number) -> Result<()>;
fn remove(&mut self, signal: Number) -> Result<()>;
fn contains(&self, signal: Number) -> Result<bool>;
fn from_signals<I>(iter: I) -> Result<Self>
where
I: IntoIterator<Item = Number>,
{
let mut set = Self::new();
for signal in iter {
set.insert(signal)?;
}
Ok(set)
}
}
pub trait Sigmask: Signals {
type Sigset: Sigset + Debug;
fn sigmask(
&self,
op: Option<(SigmaskOp, &Self::Sigset)>,
old_mask: Option<&mut Self::Sigset>,
) -> impl Future<Output = Result<()>> + use<Self>;
}
impl<S: Sigmask> Sigmask for Rc<S> {
type Sigset = S::Sigset;
#[inline]
fn sigmask(
&self,
op: Option<(SigmaskOp, &Self::Sigset)>,
old_mask: Option<&mut Self::Sigset>,
) -> impl Future<Output = Result<()>> + use<S> {
(self as &S).sigmask(op, old_mask)
}
}
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum Disposition {
#[default]
Default,
Ignore,
Catch,
}
pub trait GetSigaction: Signals {
fn get_sigaction(&self, signal: Number) -> Result<Disposition>;
}
impl<S: GetSigaction> GetSigaction for Rc<S> {
#[inline]
fn get_sigaction(&self, signal: Number) -> Result<Disposition> {
(self as &S).get_sigaction(signal)
}
}
pub trait Sigaction: GetSigaction {
fn sigaction(&self, signal: Number, action: Disposition) -> Result<Disposition>;
}
impl<S: Sigaction> Sigaction for Rc<S> {
#[inline]
fn sigaction(&self, signal: Number, action: Disposition) -> Result<Disposition> {
(self as &S).sigaction(signal, action)
}
}
pub trait CaughtSignals: Signals {
fn caught_signals(&self) -> Vec<Number>;
}
impl<S: CaughtSignals> CaughtSignals for Rc<S> {
#[inline]
fn caught_signals(&self) -> Vec<Number> {
(self as &S).caught_signals()
}
}
pub trait SendSignal: Signals {
fn kill(
&self,
target: Pid,
signal: Option<Number>,
) -> impl Future<Output = Result<()>> + use<Self>;
fn raise(&self, signal: Number) -> impl Future<Output = Result<()>> + use<Self>;
}
impl<S: SendSignal> SendSignal for Rc<S> {
#[inline]
fn kill(
&self,
target: Pid,
signal: Option<Number>,
) -> impl Future<Output = Result<()>> + use<S> {
(self as &S).kill(target, signal)
}
#[inline]
fn raise(&self, signal: Number) -> impl Future<Output = Result<()>> + use<S> {
(self as &S).raise(signal)
}
}