diff --git a/CHANGELOG.md b/CHANGELOG.md index 667a61f8..02a804ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ ## Unreleased +#### Breaking Changes + +- Remove `nix` from the public API. This replaces `Signal` with a home-grown + `Signal` enum and `siginfo` with a structure that provides most of its fields. + ## 0.13.0 -- 2024-02-25 #### Breaking changes diff --git a/src/sources/signals.rs b/src/sources/signals.rs index 8729169e..0cba53f9 100644 --- a/src/sources/signals.rs +++ b/src/sources/signals.rs @@ -15,28 +15,165 @@ use std::io::Error as IoError; use std::os::raw::c_int; use nix::sys::signal::SigSet; -pub use nix::sys::signal::Signal; -pub use nix::sys::signalfd::siginfo; -use nix::sys::signalfd::{SfdFlags, SignalFd}; +use nix::sys::signalfd::{siginfo, SfdFlags, SignalFd}; use super::generic::{FdWrapper, Generic}; use crate::{EventSource, Interest, Mode, Poll, PostAction, Readiness, Token, TokenFactory}; +// Code taken from async-signal +macro_rules! define_signal_enum { + ( + $(#[$outer:meta])* + pub enum Signal { + $( + $(#[$inner:meta])* + $value:ident, + )* + } + ) => { + $(#[$outer])* + #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)] + #[repr(i32)] + pub enum Signal { + $( + $(#[$inner])* + $value = nix::sys::signal::Signal::$value as i32, + )* + } + + impl Signal { + /// Returns the signal number. + fn as_nix(self) -> nix::sys::signal::Signal { + match self { + $( + Signal::$value => nix::sys::signal::Signal::$value, + )* + } + } + + /// Generate from a signal number. + fn from_num(id: i32) -> Self { + match nix::sys::signal::Signal::try_from(id) { + $( + Ok(nix::sys::signal::Signal::$value) => Self::$value, + )* + + Ok(sig) => panic!("unknown signal: {:?}", sig), + Err(_) => panic!("unknown signal: {}", id) + } + } + } + } +} + +define_signal_enum! { + // Copied from https://github.com/bytecodealliance/rustix/blob/main/src/backend/linux_raw/process/types.rs#L81-L161 + + /// The signal types that we are able to listen for. + pub enum Signal { + /// `SIGHUP` + SIGHUP, + /// `SIGINT` + SIGINT, + /// `SIGQUIT` + SIGQUIT, + /// `SIGILL` + SIGILL, + /// `SIGTRAP` + SIGTRAP, + /// `SIGABRT`, aka `SIGIOT` + #[doc(alias = "Iot")] + #[doc(alias = "Abrt")] + SIGABRT, + /// `SIGBUS` + SIGBUS, + /// `SIGFPE` + SIGFPE, + /// `SIGKILL` + SIGKILL, + /// `SIGUSR1` + SIGUSR1, + /// `SIGSEGV` + SIGSEGV, + /// `SIGUSR2` + SIGUSR2, + /// `SIGPIPE` + SIGPIPE, + /// `SIGALRM` + #[doc(alias = "Alrm")] + SIGALRM, + /// `SIGTERM` + SIGTERM, + /// `SIGCHLD` + #[doc(alias = "Chld")] + SIGCHLD, + /// `SIGCONT` + SIGCONT, + /// `SIGSTOP` + SIGSTOP, + /// `SIGTSTP` + SIGTSTP, + /// `SIGTTIN` + SIGTTIN, + /// `SIGTTOU` + SIGTTOU, + /// `SIGURG` + SIGURG, + /// `SIGXCPU` + SIGXCPU, + /// `SIGXFSZ` + SIGXFSZ, + /// `SIGVTALRM` + #[doc(alias = "Vtalrm")] + SIGVTALRM, + /// `SIGPROF` + SIGPROF, + /// `SIGWINCH` + SIGWINCH, + /// `SIGIO`, aka `SIGPOLL` + #[doc(alias = "Poll")] + SIGIO, + /// `SIGSYS`, aka `SIGUNUSED` + #[doc(alias = "Unused")] + SIGSYS, + } +} + /// An event generated by the signal event source #[derive(Copy, Clone, Debug)] pub struct Event { info: siginfo, } +macro_rules! inner_accessors { + ($($name:ident => $sname:ident: $ty:ty),*) => {$( + /// Gets the ` + #[doc = stringify!($sname)] + /// ` field. + pub fn $name(&self) -> $ty { + use core::convert::TryInto; + self.info.$sname.try_into().unwrap() + } + )*} +} + impl Event { /// Retrieve the signal number that was receive pub fn signal(&self) -> Signal { - Signal::try_from(self.info.ssi_signo as c_int).unwrap() + Signal::from_num(self.info.ssi_signo as c_int) } - /// Access the full `siginfo_t` associated with this signal event - pub fn full_info(&self) -> siginfo { - self.info + inner_accessors! { + errno => ssi_errno: i32, + code => ssi_code: i32, + pid => ssi_pid: u32, + uid => ssi_uid: u32, + fd => ssi_fd: i32, + tid => ssi_tid: u32, + bad => ssi_band: u32, + overrun => ssi_overrun: u32, + trapno => ssi_trapno: u32, + status => ssi_status: u32 } } @@ -52,7 +189,7 @@ impl Signals { pub fn new(signals: &[Signal]) -> crate::Result { let mut mask = SigSet::empty(); for &s in signals { - mask.add(s); + mask.add(s.as_nix()); } // Mask the signals for this thread @@ -73,7 +210,7 @@ impl Signals { /// have still been changed. pub fn add_signals(&mut self, signals: &[Signal]) -> crate::Result<()> { for &s in signals { - self.mask.add(s); + self.mask.add(s.as_nix()); } self.mask.thread_block().map_err(IoError::from)?; @@ -94,8 +231,8 @@ impl Signals { pub fn remove_signals(&mut self, signals: &[Signal]) -> crate::Result<()> { let mut removed = SigSet::empty(); for &s in signals { - self.mask.remove(s); - removed.add(s); + self.mask.remove(s.as_nix()); + removed.add(s.as_nix()); } removed.thread_unblock().map_err(IoError::from)?; @@ -116,7 +253,7 @@ impl Signals { pub fn set_signals(&mut self, signals: &[Signal]) -> crate::Result<()> { let mut new_mask = SigSet::empty(); for &s in signals { - new_mask.add(s); + new_mask.add(s.as_nix()); } self.mask.thread_unblock().map_err(IoError::from)?; diff --git a/tests/signals.rs b/tests/signals.rs index 8dc4399b..a145a11b 100644 --- a/tests/signals.rs +++ b/tests/signals.rs @@ -49,7 +49,7 @@ mod test { .unwrap(); // send ourselves a SIGUSR1 - kill(Pid::this(), Signal::SIGUSR1).unwrap(); + kill(Pid::this(), nix::sys::signal::Signal::SIGUSR1).unwrap(); event_loop .dispatch(Some(Duration::from_millis(10)), &mut signal_received) @@ -79,7 +79,7 @@ mod test { .unwrap(); // send ourselves a SIGUSR2 - kill(Pid::this(), Signal::SIGUSR2).unwrap(); + kill(Pid::this(), nix::sys::signal::Signal::SIGUSR2).unwrap(); event_loop .dispatch(Some(Duration::from_millis(10)), &mut signal_received) @@ -110,11 +110,11 @@ mod test { // block sigusr2 anyway, to not be killed by it let mut set = SigSet::empty(); - set.add(Signal::SIGUSR2); + set.add(nix::sys::signal::Signal::SIGUSR2); set.thread_block().unwrap(); // send ourselves a SIGUSR2 - kill(Pid::this(), Signal::SIGUSR2).unwrap(); + kill(Pid::this(), nix::sys::signal::Signal::SIGUSR2).unwrap(); event_loop .dispatch(Some(Duration::from_millis(10)), &mut signal_received)