Rename Signal to MainSignal
in preparation for another signal type
This commit is contained in:
parent
55e4e1dc58
commit
75243bfdad
|
@ -12,7 +12,7 @@ use watchexec::{
|
||||||
filter::tagged::TaggedFilterer,
|
filter::tagged::TaggedFilterer,
|
||||||
fs::Watcher,
|
fs::Watcher,
|
||||||
handler::PrintDisplay,
|
handler::PrintDisplay,
|
||||||
signal::Signal as InputSignal,
|
signal::source::MainSignal,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn new(args: &ArgMatches<'static>) -> Result<(InitConfig, RuntimeConfig, Arc<TaggedFilterer>)> {
|
pub fn new(args: &ArgMatches<'static>) -> Result<(InitConfig, RuntimeConfig, Arc<TaggedFilterer>)> {
|
||||||
|
@ -114,7 +114,7 @@ fn runtime(args: &ArgMatches<'static>) -> Result<(RuntimeConfig, Arc<TaggedFilte
|
||||||
return fut;
|
return fut;
|
||||||
}
|
}
|
||||||
|
|
||||||
let signals: Vec<InputSignal> = action.events.iter().flat_map(|e| e.signals()).collect();
|
let signals: Vec<MainSignal> = action.events.iter().flat_map(|e| e.signals()).collect();
|
||||||
let has_paths = action
|
let has_paths = action
|
||||||
.events
|
.events
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -122,12 +122,12 @@ fn runtime(args: &ArgMatches<'static>) -> Result<(RuntimeConfig, Arc<TaggedFilte
|
||||||
.next()
|
.next()
|
||||||
.is_some();
|
.is_some();
|
||||||
|
|
||||||
if signals.contains(&InputSignal::Terminate) {
|
if signals.contains(&MainSignal::Terminate) {
|
||||||
action.outcome(Outcome::both(Outcome::Stop, Outcome::Exit));
|
action.outcome(Outcome::both(Outcome::Stop, Outcome::Exit));
|
||||||
return fut;
|
return fut;
|
||||||
}
|
}
|
||||||
|
|
||||||
if signals.contains(&InputSignal::Interrupt) {
|
if signals.contains(&MainSignal::Interrupt) {
|
||||||
action.outcome(Outcome::both(Outcome::Stop, Outcome::Exit));
|
action.outcome(Outcome::both(Outcome::Stop, Outcome::Exit));
|
||||||
return fut;
|
return fut;
|
||||||
}
|
}
|
||||||
|
@ -139,12 +139,12 @@ fn runtime(args: &ArgMatches<'static>) -> Result<(RuntimeConfig, Arc<TaggedFilte
|
||||||
out = Outcome::both(
|
out = Outcome::both(
|
||||||
out,
|
out,
|
||||||
Outcome::Signal(match sig {
|
Outcome::Signal(match sig {
|
||||||
InputSignal::Hangup => Signal::SIGHUP,
|
MainSignal::Hangup => Signal::SIGHUP,
|
||||||
InputSignal::Interrupt => Signal::SIGINT,
|
MainSignal::Interrupt => Signal::SIGINT,
|
||||||
InputSignal::Quit => Signal::SIGQUIT,
|
MainSignal::Quit => Signal::SIGQUIT,
|
||||||
InputSignal::Terminate => Signal::SIGTERM,
|
MainSignal::Terminate => Signal::SIGTERM,
|
||||||
InputSignal::User1 => Signal::SIGUSR1,
|
MainSignal::User1 => Signal::SIGUSR1,
|
||||||
InputSignal::User2 => Signal::SIGUSR2,
|
MainSignal::User2 => Signal::SIGUSR2,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ use watchexec::{
|
||||||
config::{InitConfig, RuntimeConfig},
|
config::{InitConfig, RuntimeConfig},
|
||||||
error::ReconfigError,
|
error::ReconfigError,
|
||||||
fs::Watcher,
|
fs::Watcher,
|
||||||
signal::Signal,
|
signal::source::MainSignal,
|
||||||
Watchexec,
|
Watchexec,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -41,13 +41,13 @@ async fn main() -> Result<()> {
|
||||||
.flat_map(|event| event.signals())
|
.flat_map(|event| event.signals())
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
if sigs.iter().any(|sig| sig == &Signal::Interrupt) {
|
if sigs.iter().any(|sig| sig == &MainSignal::Interrupt) {
|
||||||
action.outcome(Outcome::Exit);
|
action.outcome(Outcome::Exit);
|
||||||
} else if sigs.iter().any(|sig| sig == &Signal::User1) {
|
} else if sigs.iter().any(|sig| sig == &MainSignal::User1) {
|
||||||
eprintln!("Switching to native for funsies");
|
eprintln!("Switching to native for funsies");
|
||||||
config.file_watcher(Watcher::Native).keep_action();
|
config.file_watcher(Watcher::Native).keep_action();
|
||||||
w.reconfigure(config)?;
|
w.reconfigure(config)?;
|
||||||
} else if sigs.iter().any(|sig| sig == &Signal::User2) {
|
} else if sigs.iter().any(|sig| sig == &MainSignal::User2) {
|
||||||
eprintln!("Switching to polling for funsies");
|
eprintln!("Switching to polling for funsies");
|
||||||
config
|
config
|
||||||
.file_watcher(Watcher::Poll(Duration::from_millis(50)))
|
.file_watcher(Watcher::Poll(Duration::from_millis(50)))
|
||||||
|
|
|
@ -4,7 +4,7 @@ use miette::Result;
|
||||||
use tokio::sync::mpsc;
|
use tokio::sync::mpsc;
|
||||||
use watchexec::{
|
use watchexec::{
|
||||||
event::{Event, Tag},
|
event::{Event, Tag},
|
||||||
signal::{self, Signal},
|
signal::{self, source::MainSignal},
|
||||||
};
|
};
|
||||||
|
|
||||||
// Run with: `env RUST_LOG=debug cargo run --example signal`,
|
// Run with: `env RUST_LOG=debug cargo run --example signal`,
|
||||||
|
@ -21,7 +21,7 @@ async fn main() -> Result<()> {
|
||||||
while let Some(e) = ev_r.recv().await {
|
while let Some(e) = ev_r.recv().await {
|
||||||
tracing::info!("event: {:?}", e);
|
tracing::info!("event: {:?}", e);
|
||||||
|
|
||||||
if e.tags.contains(&Tag::Signal(Signal::Terminate)) {
|
if e.tags.contains(&Tag::Signal(MainSignal::Terminate)) {
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,7 @@ async fn main() -> Result<()> {
|
||||||
});
|
});
|
||||||
|
|
||||||
tracing::info!("PID is {}", std::process::id());
|
tracing::info!("PID is {}", std::process::id());
|
||||||
signal::worker(er_s.clone(), ev_s.clone()).await?;
|
signal::source::worker(er_s.clone(), ev_s.clone()).await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ use std::{
|
||||||
|
|
||||||
use notify::EventKind;
|
use notify::EventKind;
|
||||||
|
|
||||||
use crate::signal::Signal;
|
use crate::signal::source::MainSignal;
|
||||||
|
|
||||||
/// An event, as far as watchexec cares about.
|
/// An event, as far as watchexec cares about.
|
||||||
#[derive(Clone, Debug, Default, Eq, PartialEq)]
|
#[derive(Clone, Debug, Default, Eq, PartialEq)]
|
||||||
|
@ -36,7 +36,7 @@ pub enum Tag {
|
||||||
FileEventKind(EventKind),
|
FileEventKind(EventKind),
|
||||||
Source(Source),
|
Source(Source),
|
||||||
Process(u32),
|
Process(u32),
|
||||||
Signal(Signal),
|
Signal(MainSignal),
|
||||||
ProcessCompletion(Option<ExitStatus>),
|
ProcessCompletion(Option<ExitStatus>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,7 +104,7 @@ impl Event {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return all signals in the event's tags.
|
/// Return all signals in the event's tags.
|
||||||
pub fn signals(&self) -> impl Iterator<Item = Signal> + '_ {
|
pub fn signals(&self) -> impl Iterator<Item = MainSignal> + '_ {
|
||||||
self.tags.iter().filter_map(|p| match p {
|
self.tags.iter().filter_map(|p| match p {
|
||||||
Tag::Signal(s) => Some(*s),
|
Tag::Signal(s) => Some(*s),
|
||||||
_ => None,
|
_ => None,
|
||||||
|
|
|
@ -1,196 +1,4 @@
|
||||||
//! Event source for signals / notifications sent to the main process.
|
//! Signal handling.
|
||||||
|
|
||||||
use tokio::{select, sync::mpsc};
|
pub mod source;
|
||||||
use tracing::{debug, trace};
|
pub mod process;
|
||||||
|
|
||||||
use crate::{
|
|
||||||
error::{CriticalError, RuntimeError},
|
|
||||||
event::{Event, Source, Tag},
|
|
||||||
};
|
|
||||||
|
|
||||||
/// A notification sent to the main (watchexec) process.
|
|
||||||
///
|
|
||||||
/// On Windows, only [`Interrupt`][Signal::Interrupt] and [`Terminate`][Signal::Terminate] will be
|
|
||||||
/// produced: they are respectively `Ctrl-C` (SIGINT) and `Ctrl-Break` (SIGBREAK). `Ctrl-Close` (the
|
|
||||||
/// equivalent of `SIGHUP` on Unix, without the semantics of configuration reload) is not supported,
|
|
||||||
/// and on console close the process will be terminated by the OS.
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
|
||||||
pub enum Signal {
|
|
||||||
/// Received when the terminal is disconnected.
|
|
||||||
///
|
|
||||||
/// On Unix, this is `SIGHUP`. On Windows, it is not produced.
|
|
||||||
///
|
|
||||||
/// This signal is available because it is a common signal used to reload configuration files,
|
|
||||||
/// and it is reasonable that either watchexec could make use of it, or that it should be passed
|
|
||||||
/// on to a sub process.
|
|
||||||
Hangup,
|
|
||||||
|
|
||||||
/// Received to indicate that the process should stop.
|
|
||||||
///
|
|
||||||
/// On Unix, this is `SIGINT`. On Windows, this is `Ctrl+C`.
|
|
||||||
///
|
|
||||||
/// This signal is generally produced by the user, so it may be handled differently than a
|
|
||||||
/// termination.
|
|
||||||
Interrupt,
|
|
||||||
|
|
||||||
/// Received to cause the process to stop and the kernel to dump its core.
|
|
||||||
///
|
|
||||||
/// On Unix, this is `SIGQUIT`. On Windows, it is not produced.
|
|
||||||
///
|
|
||||||
/// This signal is available because it is reasonable that it could be passed on to a sub
|
|
||||||
/// process, rather than terminate watchexec itself.
|
|
||||||
Quit,
|
|
||||||
|
|
||||||
/// Received to indicate that the process should stop.
|
|
||||||
///
|
|
||||||
/// On Unix, this is `SIGTERM`. On Windows, this is `Ctrl+Break`.
|
|
||||||
///
|
|
||||||
/// This signal is available for cleanup, but will generally not be passed on to a sub process
|
|
||||||
/// with no other consequence: it is expected the main process should terminate.
|
|
||||||
Terminate,
|
|
||||||
|
|
||||||
/// Received for a user or application defined purpose.
|
|
||||||
///
|
|
||||||
/// On Unix, this is `SIGUSR1`. On Windows, it is not produced.
|
|
||||||
///
|
|
||||||
/// This signal is available because it is expected that it most likely should be passed on to a
|
|
||||||
/// sub process or trigger a particular action within watchexec.
|
|
||||||
User1,
|
|
||||||
|
|
||||||
/// Received for a user or application defined purpose.
|
|
||||||
///
|
|
||||||
/// On Unix, this is `SIGUSR2`. On Windows, it is not produced.
|
|
||||||
///
|
|
||||||
/// This signal is available because it is expected that it most likely should be passed on to a
|
|
||||||
/// sub process or trigger a particular action within watchexec.
|
|
||||||
User2,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Launch the signal event worker.
|
|
||||||
///
|
|
||||||
/// While you _can_ run several, you **must** only have one. This may be enforced later.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// Direct usage:
|
|
||||||
///
|
|
||||||
/// ```no_run
|
|
||||||
/// use tokio::sync::mpsc;
|
|
||||||
/// use watchexec::signal::worker;
|
|
||||||
///
|
|
||||||
/// #[tokio::main]
|
|
||||||
/// async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
||||||
/// let (ev_s, _) = mpsc::channel(1024);
|
|
||||||
/// let (er_s, _) = mpsc::channel(64);
|
|
||||||
///
|
|
||||||
/// worker(er_s, ev_s).await?;
|
|
||||||
/// Ok(())
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
pub async fn worker(
|
|
||||||
errors: mpsc::Sender<RuntimeError>,
|
|
||||||
events: mpsc::Sender<Event>,
|
|
||||||
) -> Result<(), CriticalError> {
|
|
||||||
imp_worker(errors, events).await
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(unix)]
|
|
||||||
async fn imp_worker(
|
|
||||||
errors: mpsc::Sender<RuntimeError>,
|
|
||||||
events: mpsc::Sender<Event>,
|
|
||||||
) -> Result<(), CriticalError> {
|
|
||||||
use tokio::signal::unix::{signal, SignalKind};
|
|
||||||
|
|
||||||
debug!("launching unix signal worker");
|
|
||||||
|
|
||||||
macro_rules! listen {
|
|
||||||
($sig:ident) => {{
|
|
||||||
trace!(kind=%stringify!($sig), "listening for unix signal");
|
|
||||||
signal(SignalKind::$sig())?
|
|
||||||
}}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut s_hangup = listen!(hangup);
|
|
||||||
let mut s_interrupt = listen!(interrupt);
|
|
||||||
let mut s_quit = listen!(quit);
|
|
||||||
let mut s_terminate = listen!(terminate);
|
|
||||||
let mut s_user1 = listen!(user_defined1);
|
|
||||||
let mut s_user2 = listen!(user_defined2);
|
|
||||||
|
|
||||||
loop {
|
|
||||||
let sig = select!(
|
|
||||||
_ = s_hangup.recv() => Signal::Hangup,
|
|
||||||
_ = s_interrupt.recv() => Signal::Interrupt,
|
|
||||||
_ = s_quit.recv() => Signal::Quit,
|
|
||||||
_ = s_terminate.recv() => Signal::Terminate,
|
|
||||||
_ = s_user1.recv() => Signal::User1,
|
|
||||||
_ = s_user2.recv() => Signal::User2,
|
|
||||||
);
|
|
||||||
|
|
||||||
debug!(?sig, "received unix signal");
|
|
||||||
send_event(errors.clone(), events.clone(), sig).await?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(windows)]
|
|
||||||
async fn imp_worker(
|
|
||||||
errors: mpsc::Sender<RuntimeError>,
|
|
||||||
events: mpsc::Sender<Event>,
|
|
||||||
) -> Result<(), CriticalError> {
|
|
||||||
use tokio::signal::windows::{ctrl_break, ctrl_c};
|
|
||||||
|
|
||||||
debug!("launching windows signal worker");
|
|
||||||
|
|
||||||
macro_rules! listen {
|
|
||||||
($sig:ident) => {{
|
|
||||||
trace!(kind=%stringify!($sig), "listening for windows process notification");
|
|
||||||
$sig()?
|
|
||||||
}}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut sigint = listen!(ctrl_c);
|
|
||||||
let mut sigbreak = listen!(ctrl_break);
|
|
||||||
|
|
||||||
loop {
|
|
||||||
let sig = select!(
|
|
||||||
_ = sigint.recv() => Signal::Interrupt,
|
|
||||||
_ = sigbreak.recv() => Signal::Terminate,
|
|
||||||
);
|
|
||||||
|
|
||||||
debug!(?sig, "received windows process notification");
|
|
||||||
send_event(errors.clone(), events.clone(), sig).await?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: figure out how to prioritise signals.
|
|
||||||
async fn send_event(
|
|
||||||
errors: mpsc::Sender<RuntimeError>,
|
|
||||||
events: mpsc::Sender<Event>,
|
|
||||||
sig: Signal,
|
|
||||||
) -> Result<(), CriticalError> {
|
|
||||||
let tags = vec![
|
|
||||||
Tag::Source(if sig == Signal::Interrupt {
|
|
||||||
Source::Keyboard
|
|
||||||
} else {
|
|
||||||
Source::Os
|
|
||||||
}),
|
|
||||||
Tag::Signal(sig),
|
|
||||||
];
|
|
||||||
|
|
||||||
let event = Event {
|
|
||||||
tags,
|
|
||||||
metadata: Default::default(),
|
|
||||||
};
|
|
||||||
|
|
||||||
trace!(?event, "processed signal into event");
|
|
||||||
if let Err(err) = events.send(event).await {
|
|
||||||
errors
|
|
||||||
.send(RuntimeError::EventChannelSend {
|
|
||||||
ctx: "signals",
|
|
||||||
err,
|
|
||||||
})
|
|
||||||
.await?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,196 @@
|
||||||
|
//! Event source for signals / notifications sent to the main process.
|
||||||
|
|
||||||
|
use tokio::{select, sync::mpsc};
|
||||||
|
use tracing::{debug, trace};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
error::{CriticalError, RuntimeError},
|
||||||
|
event::{Event, Source, Tag},
|
||||||
|
};
|
||||||
|
|
||||||
|
/// A notification sent to the main (watchexec) process.
|
||||||
|
///
|
||||||
|
/// On Windows, only [`Interrupt`][MainSignal::Interrupt] and [`Terminate`][MainSignal::Terminate]
|
||||||
|
/// will be produced: they are respectively `Ctrl-C` (SIGINT) and `Ctrl-Break` (SIGBREAK).
|
||||||
|
/// `Ctrl-Close` (the equivalent of `SIGHUP` on Unix, without the semantics of configuration reload)
|
||||||
|
/// is not supported, and on console close the process will be terminated by the OS.
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
pub enum MainSignal {
|
||||||
|
/// Received when the terminal is disconnected.
|
||||||
|
///
|
||||||
|
/// On Unix, this is `SIGHUP`. On Windows, it is not produced.
|
||||||
|
///
|
||||||
|
/// This signal is available because it is a common signal used to reload configuration files,
|
||||||
|
/// and it is reasonable that either watchexec could make use of it, or that it should be passed
|
||||||
|
/// on to a sub process.
|
||||||
|
Hangup,
|
||||||
|
|
||||||
|
/// Received to indicate that the process should stop.
|
||||||
|
///
|
||||||
|
/// On Unix, this is `SIGINT`. On Windows, this is `Ctrl+C`.
|
||||||
|
///
|
||||||
|
/// This signal is generally produced by the user, so it may be handled differently than a
|
||||||
|
/// termination.
|
||||||
|
Interrupt,
|
||||||
|
|
||||||
|
/// Received to cause the process to stop and the kernel to dump its core.
|
||||||
|
///
|
||||||
|
/// On Unix, this is `SIGQUIT`. On Windows, it is not produced.
|
||||||
|
///
|
||||||
|
/// This signal is available because it is reasonable that it could be passed on to a sub
|
||||||
|
/// process, rather than terminate watchexec itself.
|
||||||
|
Quit,
|
||||||
|
|
||||||
|
/// Received to indicate that the process should stop.
|
||||||
|
///
|
||||||
|
/// On Unix, this is `SIGTERM`. On Windows, this is `Ctrl+Break`.
|
||||||
|
///
|
||||||
|
/// This signal is available for cleanup, but will generally not be passed on to a sub process
|
||||||
|
/// with no other consequence: it is expected the main process should terminate.
|
||||||
|
Terminate,
|
||||||
|
|
||||||
|
/// Received for a user or application defined purpose.
|
||||||
|
///
|
||||||
|
/// On Unix, this is `SIGUSR1`. On Windows, it is not produced.
|
||||||
|
///
|
||||||
|
/// This signal is available because it is expected that it most likely should be passed on to a
|
||||||
|
/// sub process or trigger a particular action within watchexec.
|
||||||
|
User1,
|
||||||
|
|
||||||
|
/// Received for a user or application defined purpose.
|
||||||
|
///
|
||||||
|
/// On Unix, this is `SIGUSR2`. On Windows, it is not produced.
|
||||||
|
///
|
||||||
|
/// This signal is available because it is expected that it most likely should be passed on to a
|
||||||
|
/// sub process or trigger a particular action within watchexec.
|
||||||
|
User2,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Launch the signal event worker.
|
||||||
|
///
|
||||||
|
/// While you _can_ run several, you **must** only have one. This may be enforced later.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// Direct usage:
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// use tokio::sync::mpsc;
|
||||||
|
/// use watchexec::signal::worker;
|
||||||
|
///
|
||||||
|
/// #[tokio::main]
|
||||||
|
/// async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
/// let (ev_s, _) = mpsc::channel(1024);
|
||||||
|
/// let (er_s, _) = mpsc::channel(64);
|
||||||
|
///
|
||||||
|
/// worker(er_s, ev_s).await?;
|
||||||
|
/// Ok(())
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
pub async fn worker(
|
||||||
|
errors: mpsc::Sender<RuntimeError>,
|
||||||
|
events: mpsc::Sender<Event>,
|
||||||
|
) -> Result<(), CriticalError> {
|
||||||
|
imp_worker(errors, events).await
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
async fn imp_worker(
|
||||||
|
errors: mpsc::Sender<RuntimeError>,
|
||||||
|
events: mpsc::Sender<Event>,
|
||||||
|
) -> Result<(), CriticalError> {
|
||||||
|
use tokio::signal::unix::{signal, SignalKind};
|
||||||
|
|
||||||
|
debug!("launching unix signal worker");
|
||||||
|
|
||||||
|
macro_rules! listen {
|
||||||
|
($sig:ident) => {{
|
||||||
|
trace!(kind=%stringify!($sig), "listening for unix signal");
|
||||||
|
signal(SignalKind::$sig())?
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut s_hangup = listen!(hangup);
|
||||||
|
let mut s_interrupt = listen!(interrupt);
|
||||||
|
let mut s_quit = listen!(quit);
|
||||||
|
let mut s_terminate = listen!(terminate);
|
||||||
|
let mut s_user1 = listen!(user_defined1);
|
||||||
|
let mut s_user2 = listen!(user_defined2);
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let sig = select!(
|
||||||
|
_ = s_hangup.recv() => MainSignal::Hangup,
|
||||||
|
_ = s_interrupt.recv() => MainSignal::Interrupt,
|
||||||
|
_ = s_quit.recv() => MainSignal::Quit,
|
||||||
|
_ = s_terminate.recv() => MainSignal::Terminate,
|
||||||
|
_ = s_user1.recv() => MainSignal::User1,
|
||||||
|
_ = s_user2.recv() => MainSignal::User2,
|
||||||
|
);
|
||||||
|
|
||||||
|
debug!(?sig, "received unix signal");
|
||||||
|
send_event(errors.clone(), events.clone(), sig).await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
async fn imp_worker(
|
||||||
|
errors: mpsc::Sender<RuntimeError>,
|
||||||
|
events: mpsc::Sender<Event>,
|
||||||
|
) -> Result<(), CriticalError> {
|
||||||
|
use tokio::signal::windows::{ctrl_break, ctrl_c};
|
||||||
|
|
||||||
|
debug!("launching windows signal worker");
|
||||||
|
|
||||||
|
macro_rules! listen {
|
||||||
|
($sig:ident) => {{
|
||||||
|
trace!(kind=%stringify!($sig), "listening for windows process notification");
|
||||||
|
$sig()?
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut sigint = listen!(ctrl_c);
|
||||||
|
let mut sigbreak = listen!(ctrl_break);
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let sig = select!(
|
||||||
|
_ = sigint.recv() => MainSignal::Interrupt,
|
||||||
|
_ = sigbreak.recv() => MainSignal::Terminate,
|
||||||
|
);
|
||||||
|
|
||||||
|
debug!(?sig, "received windows process notification");
|
||||||
|
send_event(errors.clone(), events.clone(), sig).await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: figure out how to prioritise signals.
|
||||||
|
async fn send_event(
|
||||||
|
errors: mpsc::Sender<RuntimeError>,
|
||||||
|
events: mpsc::Sender<Event>,
|
||||||
|
sig: MainSignal,
|
||||||
|
) -> Result<(), CriticalError> {
|
||||||
|
let tags = vec![
|
||||||
|
Tag::Source(if sig == MainSignal::Interrupt {
|
||||||
|
Source::Keyboard
|
||||||
|
} else {
|
||||||
|
Source::Os
|
||||||
|
}),
|
||||||
|
Tag::Signal(sig),
|
||||||
|
];
|
||||||
|
|
||||||
|
let event = Event {
|
||||||
|
tags,
|
||||||
|
metadata: Default::default(),
|
||||||
|
};
|
||||||
|
|
||||||
|
trace!(?event, "processed signal into event");
|
||||||
|
if let Err(err) = events.send(event).await {
|
||||||
|
errors
|
||||||
|
.send(RuntimeError::EventChannelSend {
|
||||||
|
ctx: "signals",
|
||||||
|
err,
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -86,7 +86,7 @@ impl Watchexec {
|
||||||
action::worker(ac_r, er_s.clone(), ev_s.clone(), ev_r)
|
action::worker(ac_r, er_s.clone(), ev_s.clone(), ev_r)
|
||||||
);
|
);
|
||||||
let fs = subtask!(fs, fs::worker(fs_r, er_s.clone(), ev_s.clone()));
|
let fs = subtask!(fs, fs::worker(fs_r, er_s.clone(), ev_s.clone()));
|
||||||
let signal = subtask!(signal, signal::worker(er_s.clone(), ev_s.clone()));
|
let signal = subtask!(signal, signal::source::worker(er_s.clone(), ev_s.clone()));
|
||||||
|
|
||||||
let error_hook = subtask!(error_hook, error_hook(er_r, eh));
|
let error_hook = subtask!(error_hook, error_hook(er_r, eh));
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue