From 7ea7d2629d8cd680824d43faf63e9935ccdf1543 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fe=CC=81lix=20Saparelli?= Date: Sat, 9 Dec 2023 23:06:10 +1300 Subject: [PATCH 1/2] signals: add first-class SIGSTOP etc --- crates/signals/CHANGELOG.md | 1 + crates/signals/src/lib.rs | 48 +++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/crates/signals/CHANGELOG.md b/crates/signals/CHANGELOG.md index 4cf0bc7..98a9ccd 100644 --- a/crates/signals/CHANGELOG.md +++ b/crates/signals/CHANGELOG.md @@ -3,6 +3,7 @@ ## Next (YYYY-MM-DD) - 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 3972eac..5e3e817 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")), @@ -322,6 +355,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); } @@ -358,6 +394,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 { @@ -370,6 +412,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), } } @@ -385,6 +430,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), } } From c5a1cca81c95a8091965a918ac766a1c02a44538 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fe=CC=81lix=20Saparelli?= Date: Sat, 9 Dec 2023 23:20:03 +1300 Subject: [PATCH 2/2] WIP: listen for SIGSTOP in lib --- crates/lib/src/sources/signal.rs | 42 ++++++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 7 deletions(-) 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");