diff --git a/crates/lib/src/sources/signal.rs b/crates/lib/src/sources/signal.rs index 1f39e86..5d7b1e4 100644 --- a/crates/lib/src/sources/signal.rs +++ b/crates/lib/src/sources/signal.rs @@ -55,13 +55,14 @@ async fn imp_worker( debug!("launching unix signal worker"); macro_rules! listen { - ($sig:ident) => {{ - trace!(kind=%stringify!($sig), "listening for unix signal"); - signal(SignalKind::$sig()).map_err(|err| CriticalError::IoError { - about: concat!("setting ", stringify!($sig), " signal listener"), err - })? - }} -} + ($sig:ident, $signum:expr) => {{ + trace!(kind=%stringify!($sig), "listening for unix signal"); + signal($signum).map_err(|err| CriticalError::IoError { + about: concat!("setting ", stringify!($sig), " signal listener"), err + })? + }}; + ($sig:ident) => (listen!($sig, SignalKind::$sig())); + } let mut s_hangup = listen!(hangup); let mut s_interrupt = listen!(interrupt); @@ -70,6 +71,30 @@ async fn imp_worker( let mut s_user1 = listen!(user_defined1); let mut s_user2 = listen!(user_defined2); + // TODO: option to customise set of signals being listened to, so we can safely listen to sigstop only when requested + + let mut s_tstp = if let Some(signum) = Signal::TerminalSuspend.to_nix().map(|s| s as i32) { + listen!(terminal_suspend, SignalKind::from_raw(signum)) + } else { + signal(SignalKind::from_raw(9)).map_err(|err| CriticalError::IoError { + about: concat!("setting unreceivable signal listener"), err + })? + }; + let mut s_stop = if let Some(signum) = Signal::Suspend.to_nix().map(|s| s as i32) { + listen!(suspend, SignalKind::from_raw(signum)) + } else { + signal(SignalKind::from_raw(9)).map_err(|err| CriticalError::IoError { + about: concat!("setting unreceivable signal listener"), err + })? + }; + let mut s_cont = if let Some(signum) = Signal::Continue.to_nix().map(|s| s as i32) { + listen!(r#continue, SignalKind::from_raw(signum)) + } else { + signal(SignalKind::from_raw(9)).map_err(|err| CriticalError::IoError { + about: concat!("setting unreceivable signal listener"), err + })? + }; + loop { let sig = select!( _ = s_hangup.recv() => Signal::Hangup, @@ -78,6 +103,9 @@ async fn imp_worker( _ = s_terminate.recv() => Signal::Terminate, _ = s_user1.recv() => Signal::User1, _ = s_user2.recv() => Signal::User2, + _ = s_tstp.recv() => Signal::TerminalSuspend, + _ = s_stop.recv() => Signal::Suspend, + _ = s_cont.recv() => Signal::Continue, ); debug!(?sig, "received unix signal"); diff --git a/crates/signals/CHANGELOG.md b/crates/signals/CHANGELOG.md index c26163c..1842a5e 100644 --- a/crates/signals/CHANGELOG.md +++ b/crates/signals/CHANGELOG.md @@ -10,6 +10,7 @@ ## v2.1.0 (2023-12-09) - Derive `Hash` for `Signal`. +- Add `Continue`, `Suspend`, and `TerminalSuspend` as first-class signals. ## v2.0.0 (2023-11-29) diff --git a/crates/signals/src/lib.rs b/crates/signals/src/lib.rs index c80e2b1..3d72b3b 100644 --- a/crates/signals/src/lib.rs +++ b/crates/signals/src/lib.rs @@ -85,6 +85,27 @@ pub enum Signal { /// This signal is generally used to reload configuration. User2, + /// Sent to a process to unsuspend it. + /// + /// On Unix, this is `SIGCONT`. On Windows, it is ignored. + /// + /// See also [`Suspend`](Signal::Suspend) and [`TerminalSuspend`][Signal::TerminalSuspend]. + Continue, + + /// Indicate that the process should suspend itself. + /// + /// On Unix, this is `SIGSTOP`. On Windows, it is ignored. + /// + /// See also [`TerminalSuspend`][Signal::TerminalSuspend]. + Suspend, + + /// Indicate that the process should suspend itself (issued from the terminal). + /// + /// On Unix, this is `SIGTSTP`. On Windows, it is ignored. + /// + /// See also [`Suspend`][Signal::Suspend]. + TerminalSuspend, + /// Indicate using a custom signal. /// /// Internally, this is converted to a [`nix::Signal`](https://docs.rs/nix/*/nix/sys/signal/enum.Signal.html) @@ -137,6 +158,9 @@ impl Signal { Self::Terminate => Some(NixSignal::SIGTERM), Self::User1 => Some(NixSignal::SIGUSR1), Self::User2 => Some(NixSignal::SIGUSR2), + Self::Suspend => Some(NixSignal::SIGSTOP), + Self::TerminalSuspend => Some(NixSignal::SIGTSTP), + Self::Continue => Some(NixSignal::SIGCONT), Self::Custom(sig) => NixSignal::try_from(sig).ok(), } } @@ -154,6 +178,9 @@ impl Signal { NixSignal::SIGTERM => Self::Terminate, NixSignal::SIGUSR1 => Self::User1, NixSignal::SIGUSR2 => Self::User2, + NixSignal::SIGSTOP => Self::Suspend, + NixSignal::SIGTSTP => Self::TerminalSuspend, + NixSignal::SIGCONT => Self::Continue, sig => Self::Custom(sig as _), } } @@ -172,6 +199,9 @@ impl From for Signal { 10 => Self::User1, 12 => Self::User2, 15 => Self::Terminate, + 18 => Self::Continue, + 19 => Self::Suspend, + 20 => Self::TerminalSuspend, _ => Self::Custom(raw), } } @@ -228,6 +258,9 @@ impl Signal { "TERM" | "SIGTERM" | "15" => Ok(Self::Terminate), "USR1" | "SIGUSR1" | "10" => Ok(Self::User1), "USR2" | "SIGUSR2" | "12" => Ok(Self::User2), + "CONT" | "SIGCONT" | "18" => Ok(Self::Continue), + "STOP" | "SIGSTOP" | "19" => Ok(Self::Suspend), + "TSTP" | "SIGTSTP" | "20" => Ok(Self::TerminalSuspend), number => match i32::from_str(number) { Ok(int) => Ok(Self::Custom(int)), Err(_) => Err(SignalParseError::new(s, "unsupported signal")), @@ -323,6 +356,9 @@ impl fmt::Display for Signal { (Self::Terminate, true) => "CTRL-BREAK", (Self::User1, _) => "SIGUSR1", (Self::User2, _) => "SIGUSR2", + (Self::Continue, _) => "SIGCONT", + (Self::Suspend, _) => "SIGSTOP", + (Self::TerminalSuspend, _) => "SIGTSTP", (Self::Custom(n), _) => { return write!(f, "{n}"); } @@ -359,6 +395,12 @@ mod serde_support { User1, #[serde(rename = "SIGUSR2")] User2, + #[serde(rename = "SIGCONT")] + Continue, + #[serde(rename = "SIGSTOP")] + Suspend, + #[serde(rename = "SIGTSTP")] + TerminalSuspend, } impl From for SerdeSignal { @@ -371,6 +413,9 @@ mod serde_support { Signal::User1 => Self::Named(NamedSignal::User1), Signal::User2 => Self::Named(NamedSignal::User2), Signal::ForceStop => Self::Named(NamedSignal::ForceStop), + Signal::Continue => Self::Named(NamedSignal::Continue), + Signal::Suspend => Self::Named(NamedSignal::Suspend), + Signal::TerminalSuspend => Self::Named(NamedSignal::TerminalSuspend), Signal::Custom(number) => Self::Number(number), } } @@ -386,6 +431,9 @@ mod serde_support { SerdeSignal::Named(NamedSignal::Terminate) => Self::Terminate, SerdeSignal::Named(NamedSignal::User1) => Self::User1, SerdeSignal::Named(NamedSignal::User2) => Self::User2, + SerdeSignal::Named(NamedSignal::Continue) => Self::Continue, + SerdeSignal::Named(NamedSignal::Suspend) => Self::Suspend, + SerdeSignal::Named(NamedSignal::TerminalSuspend) => Self::TerminalSuspend, SerdeSignal::Number(number) => Self::Custom(number), } }