Compare commits

...

4 Commits

Author SHA1 Message Date
Félix Saparelli 58f92d5cfb
Merge c5a1cca81c into a4df258735 2024-04-27 23:55:27 +12:00
Félix Saparelli a4df258735
doc: fix --on-busy-update help text (#825) 2024-04-23 14:44:59 +12:00
Félix Saparelli c5a1cca81c
WIP: listen for SIGSTOP in lib 2023-12-09 23:20:03 +13:00
Félix Saparelli 7ea7d2629d
signals: add first-class SIGSTOP etc 2023-12-09 23:08:18 +13:00
6 changed files with 102 additions and 32 deletions

View File

@ -145,17 +145,14 @@ pub struct Args {
/// What to do when receiving events while the command is running
///
/// Default is to 'queue' up events and run the command once again when the previous run has
/// finished. You can also use 'do-nothing', which ignores events while the command is running
/// and may be useful to avoid spurious changes made by that command, or 'restart', which
/// terminates the running command and starts a new one. Finally, there's 'signal', which only
/// sends a signal; this can be useful with programs that can reload their configuration without
/// a full restart.
/// Default is to 'do-nothing', which ignores events while the command is running, so that
/// changes that occur due to the command are ignored, like compilation outputs. You can also
/// use 'queue' which will run the command once again when the current run has finished if any
/// events occur while it's running, or 'restart', which terminates the running command and starts
/// a new one. Finally, there's 'signal', which only sends a signal; this can be useful with
/// programs that can reload their configuration without a full restart.
///
/// The signal can be specified with the '--signal' option.
///
/// Note that this option is scheduled to change its default to 'do-nothing' in the next major
/// release. File an issue if you have any concerns.
#[arg(
short,
long,

View File

@ -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");

View File

@ -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)

View File

@ -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<i32> 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<Signal> 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),
}
}

View File

@ -1,6 +1,6 @@
.ie \n(.g .ds Aq \(aq
.el .ds Aq '
.TH watchexec 1 "watchexec 1.25.1"
.TH watchexec 1 "watchexec 2.0.0"
.SH NAME
watchexec \- Execute commands when watched files change
.SH SYNOPSIS
@ -56,11 +56,9 @@ If this doesn\*(Aqt completely clear the screen, try \*(Aq\-\-clear=reset\*(Aq.
\fB\-o\fR, \fB\-\-on\-busy\-update\fR=\fIMODE\fR
What to do when receiving events while the command is running
Default is to \*(Aqqueue\*(Aq up events and run the command once again when the previous run has finished. You can also use \*(Aqdo\-nothing\*(Aq, which ignores events while the command is running and may be useful to avoid spurious changes made by that command, or \*(Aqrestart\*(Aq, which terminates the running command and starts a new one. Finally, there\*(Aqs \*(Aqsignal\*(Aq, which only sends a signal; this can be useful with programs that can reload their configuration without a full restart.
Default is to \*(Aqdo\-nothing\*(Aq, which ignores events while the command is running, so that changes that occur due to the command are ignored, like compilation outputs. You can also use \*(Aqqueue\*(Aq which will run the command once again when the current run has finished if any events occur while it\*(Aqs running, or \*(Aqrestart\*(Aq, which terminates the running command and starts a new one. Finally, there\*(Aqs \*(Aqsignal\*(Aq, which only sends a signal; this can be useful with programs that can reload their configuration without a full restart.
The signal can be specified with the \*(Aq\-\-signal\*(Aq option.
Note that this option is scheduled to change its default to \*(Aqdo\-nothing\*(Aq in the next major release. File an issue if you have any concerns.
.TP
\fB\-r\fR, \fB\-\-restart\fR
Restart the process if it\*(Aqs still running
@ -577,6 +575,6 @@ Use @argfile as first argument to load arguments from the file \*(Aqargfile\*(Aq
Didn\*(Aqt expect this much output? Use the short \*(Aq\-h\*(Aq flag to get short help.
.SH VERSION
v1.25.1
v2.0.0
.SH AUTHORS
Félix Saparelli <felix@passcod.name>, Matt Green <mattgreenrocks@gmail.com>

View File

@ -92,19 +92,17 @@ If this doesnt completely clear the screen, try \--clear=reset.
: What to do when receiving events while the command is running
Default is to queue up events and run the command once again when the
previous run has finished. You can also use do-nothing, which ignores
events while the command is running and may be useful to avoid spurious
changes made by that command, or restart, which terminates the running
command and starts a new one. Finally, theres signal, which only sends a
signal; this can be useful with programs that can reload their
configuration without a full restart.
Default is to do-nothing, which ignores events while the command is
running, so that changes that occur due to the command are ignored, like
compilation outputs. You can also use queue which will run the command
once again when the current run has finished if any events occur while
its running, or restart, which terminates the running command and starts
a new one. Finally, theres signal, which only sends a signal; this can
be useful with programs that can reload their configuration without a
full restart.
The signal can be specified with the \--signal option.
Note that this option is scheduled to change its default to do-nothing
in the next major release. File an issue if you have any concerns.
**-r**, **\--restart**
: Restart the process if its still running
@ -852,7 +850,7 @@ Didnt expect this much output? Use the short -h flag to get short help.
# VERSION
v1.25.1
v2.0.0
# AUTHORS