commit
00a339a2f1
|
@ -56,7 +56,11 @@ Call/restart `python server.py` when any Python file in the current directory (a
|
|||
|
||||
Call/restart `my_server` when any file in the current directory (and all subdirectories) changes, sending `SIGKILL` to stop the child process:
|
||||
|
||||
$ watchexec -r -k my_server
|
||||
$ watchexec -r -s SIGKILL my_server
|
||||
|
||||
Send a SIGHUP to the child process upon changes:
|
||||
|
||||
$ watchexec -s SIGHUP my_server
|
||||
|
||||
Run `make` when any file changes, using the `.gitignore` file in the current directory to filter:
|
||||
|
||||
|
|
|
@ -30,8 +30,8 @@ Comma\-separated list of file extensions to filter by\. Leading dots are allowed
|
|||
Ignores modifications from paths that do not match \fIpattern\fR\. This option can be specified multiple times, where a match on any given pattern causes the path to trigger \fIcommand\fR\.
|
||||
.
|
||||
.TP
|
||||
\fB\-k\fR, \fB\-\-kill\fR
|
||||
Send \fBSIGKILL\fR to the child process group instead of \fBSIGTERM\fR\.
|
||||
\fB\-s\fR, \fB\-\-signal <SIGKILL|SIGHUP|...>\fR
|
||||
Sends the specified signal (e\.g\. \fBSIGKILL\fR) to the child process\. Defaults to \fBSIGTERM\fR\.
|
||||
.
|
||||
.TP
|
||||
\fB\-i\fR, \fB\-\-ignore\fR \fIpattern\fR
|
||||
|
|
|
@ -88,7 +88,7 @@
|
|||
<dt class="flush"><var>command</var></dt><dd><p>Command to run when watched files are modified, and at startup, unless <code>--postpone</code> is specified. All <var>argument</var>s are passed to <var>command</var>.</p></dd>
|
||||
<dt><code>-e</code>, <code>--exts</code> <var>extensions</var></dt><dd><p>Comma-separated list of file extensions to filter by. Leading dots are allowed (.rs) are allowed. (This is a shorthand for <code>-f</code>).</p></dd>
|
||||
<dt><code>-f</code>, <code>--filter</code> <var>pattern</var></dt><dd><p>Ignores modifications from paths that do not match <var>pattern</var>. This option can be specified multiple times, where a match on any given pattern causes the path to trigger <var>command</var>.</p></dd>
|
||||
<dt><code>-k</code>, <code>--kill</code></dt><dd><p>Send <code>SIGKILL</code> to the child process group instead of <code>SIGTERM</code>.</p></dd>
|
||||
<dt><code>-s</code>, <code>--signal</code> <var>SIGNAL</var></dt><dd><p> Sends the specified signal (e.g. <code>SIGKILl</code>) to the child process. Defaults to <code>SIGTERM</code>.</p></dd>
|
||||
<dt><code>-i</code>, <code>--ignore</code> <var>pattern</var></dt><dd><p>Ignores modifications from paths that match <var>pattern</var>. This option can be specified multiple times, and a match on any pattern causes the path to be ignored.</p></dd>
|
||||
<dt><code>-w</code>, <code>--watch</code> <var>path</var></dt><dd><p>Monitor a specific path for changes. By default, the current working directory is watched. This may be specified multiple times, where a change in any watched directory (and subdirectories) causes <var>command</var> to be executed.</p></dd>
|
||||
<dt><code>-r</code>, <code>--restart</code></dt><dd><p>Terminates the child process group if it is still running when subsequent file modifications are detected. By default, sends <code>SIGTERM</code>; use <code>--kill</code> to send <code>SIGKILL</code>.</p></dd>
|
||||
|
|
|
@ -22,8 +22,8 @@ Comma-separated list of file extensions to filter by. Leading dots are allowed (
|
|||
* `-f`, `--filter` <pattern>:
|
||||
Ignores modifications from paths that do not match <pattern>. This option can be specified multiple times, where a match on any given pattern causes the path to trigger <command>.
|
||||
|
||||
* `-k`, `--kill`:
|
||||
Send `SIGKILL` to the child process group instead of `SIGTERM`.
|
||||
* `-s`, `--signal`:
|
||||
Sends the specified signal (e.g. `SIGKILL`) to the child process. Defaults to `SIGTERM`.
|
||||
|
||||
* `-i`, `--ignore` <pattern>:
|
||||
Ignores modifications from paths that match <pattern>. This option can be specified multiple times, and a match on any pattern causes the path to be ignored.
|
||||
|
|
47
src/cli.rs
47
src/cli.rs
|
@ -1,7 +1,7 @@
|
|||
use std::path::MAIN_SEPARATOR;
|
||||
use std::process::Command;
|
||||
|
||||
use clap::{App, Arg};
|
||||
use clap::{App, Arg, Error};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Args {
|
||||
|
@ -10,7 +10,7 @@ pub struct Args {
|
|||
pub filters: Vec<String>,
|
||||
pub ignores: Vec<String>,
|
||||
pub clear_screen: bool,
|
||||
pub kill: bool,
|
||||
pub signal: Option<String>,
|
||||
pub restart: bool,
|
||||
pub debug: bool,
|
||||
pub run_initially: bool,
|
||||
|
@ -60,6 +60,17 @@ pub fn get_args() -> Args {
|
|||
.help("Restart the process if it's still running")
|
||||
.short("r")
|
||||
.long("restart"))
|
||||
.arg(Arg::with_name("signal")
|
||||
.help("Send signal to process upon changes, e.g. SIGHUP")
|
||||
.short("s")
|
||||
.long("signal")
|
||||
.takes_value(true)
|
||||
.number_of_values(1)
|
||||
.value_name("signal"))
|
||||
.arg(Arg::with_name("kill")
|
||||
.help("Send SIGKILL to child processes (deprecated, use -s SIGKILL instead)")
|
||||
.short("k")
|
||||
.long("kill"))
|
||||
.arg(Arg::with_name("debug")
|
||||
.help("Print debugging messages to stderr")
|
||||
.short("d")
|
||||
|
@ -91,18 +102,20 @@ pub fn get_args() -> Args {
|
|||
.help("Forces polling mode")
|
||||
.long("force-poll")
|
||||
.value_name("interval"))
|
||||
.arg(Arg::with_name("kill")
|
||||
.help("Send SIGKILL to child processes")
|
||||
.short("k")
|
||||
.long("kill"))
|
||||
.arg(Arg::with_name("once")
|
||||
.short("1")
|
||||
.hidden(true))
|
||||
.arg(Arg::with_name("once").short("1").hidden(true))
|
||||
.get_matches();
|
||||
|
||||
let cmd = values_t!(args.values_of("command"), String).unwrap().join(" ");
|
||||
let cmd = values_t!(args.values_of("command"), String)
|
||||
.unwrap()
|
||||
.join(" ");
|
||||
let paths = values_t!(args.values_of("path"), String).unwrap_or(vec![String::from(".")]);
|
||||
|
||||
// Treat --kill as --signal SIGKILL (for compatibility with older syntax)
|
||||
let signal = match args.is_present("kill") {
|
||||
true => Some("SIGKILL".to_string()),
|
||||
false => args.value_of("signal").map(str::to_string), // Convert Option<&str> to Option<String>
|
||||
};
|
||||
|
||||
let mut filters = values_t!(args.values_of("filter"), String).unwrap_or(vec![]);
|
||||
|
||||
if let Some(extensions) = args.values_of("extensions") {
|
||||
|
@ -129,13 +142,25 @@ pub fn get_args() -> Args {
|
|||
1000
|
||||
};
|
||||
|
||||
if signal.is_some() && args.is_present("postpone") {
|
||||
// TODO: Error::argument_conflict() might be the better fit, usage was unclear, though
|
||||
Error::value_validation_auto(format!("--postpone and --signal are mutually exclusive"))
|
||||
.exit();
|
||||
}
|
||||
|
||||
if signal.is_some() && args.is_present("kill") {
|
||||
// TODO: Error::argument_conflict() might be the better fit, usage was unclear, though
|
||||
Error::value_validation_auto(format!("--kill and --signal is ambiguous.\n Hint: Use only '--signal SIGKILL' without --kill"))
|
||||
.exit();
|
||||
}
|
||||
|
||||
Args {
|
||||
cmd: cmd,
|
||||
paths: paths,
|
||||
filters: filters,
|
||||
ignores: ignores,
|
||||
signal: signal,
|
||||
clear_screen: args.is_present("clear"),
|
||||
kill: args.is_present("kill"),
|
||||
restart: args.is_present("restart"),
|
||||
debug: args.is_present("debug"),
|
||||
run_initially: !args.is_present("postpone"),
|
||||
|
|
|
@ -137,9 +137,7 @@ impl GitignoreFile {
|
|||
pat = pat + "/**";
|
||||
}
|
||||
|
||||
let glob = try!(GlobBuilder::new(&pat)
|
||||
.literal_separator(true)
|
||||
.build());
|
||||
let glob = try!(GlobBuilder::new(&pat).literal_separator(true).build());
|
||||
|
||||
builder.add(glob);
|
||||
patterns.push(p);
|
||||
|
@ -182,7 +180,8 @@ impl GitignoreFile {
|
|||
}
|
||||
|
||||
fn parse(contents: Vec<&str>) -> Vec<Pattern> {
|
||||
contents.iter()
|
||||
contents
|
||||
.iter()
|
||||
.filter(|l| !l.is_empty())
|
||||
.filter(|l| !l.starts_with('#'))
|
||||
.map(|l| Pattern::parse(l))
|
||||
|
|
96
src/main.rs
96
src/main.rs
|
@ -45,7 +45,8 @@ fn init_logger(debug: bool) {
|
|||
log::LogLevelFilter::Warn
|
||||
};
|
||||
|
||||
log_builder.format(|r| format!("*** {}", r.args()))
|
||||
log_builder
|
||||
.format(|r| format!("*** {}", r.args()))
|
||||
.filter(None, level);
|
||||
log_builder.init().expect("unable to initialize logger");
|
||||
}
|
||||
|
@ -54,23 +55,17 @@ fn main() {
|
|||
let args = cli::get_args();
|
||||
let child_process: Arc<RwLock<Option<Process>>> = Arc::new(RwLock::new(None));
|
||||
let weak_child = Arc::downgrade(&child_process);
|
||||
let kill = args.kill;
|
||||
|
||||
// Convert signal string to the corresponding integer
|
||||
let signal = signal::new(args.signal);
|
||||
|
||||
signal::install_handler(move |sig: Signal| {
|
||||
if let Some(lock) = weak_child.upgrade() {
|
||||
let strong = lock.read().unwrap();
|
||||
if let Some(ref child) = *strong {
|
||||
match sig {
|
||||
Signal::Terminate => {
|
||||
if kill {
|
||||
child.kill();
|
||||
} else {
|
||||
child.terminate();
|
||||
}
|
||||
}
|
||||
Signal::Stop => child.pause(),
|
||||
Signal::Continue => child.resume(),
|
||||
Signal::ChildExit => child.reap(),
|
||||
Signal::SIGCHLD => child.reap(), // SIGCHLD is special, initiate reap()
|
||||
_ => child.signal(sig),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -98,8 +93,8 @@ fn main() {
|
|||
.expect("unable to create notification filter");
|
||||
|
||||
let (tx, rx) = channel();
|
||||
let watcher = Watcher::new(tx, &paths, args.poll, args.poll_interval)
|
||||
.expect("unable to create watcher");
|
||||
let watcher =
|
||||
Watcher::new(tx, &paths, args.poll, args.poll_interval).expect("unable to create watcher");
|
||||
|
||||
if watcher.is_polling() {
|
||||
warn!("Polling for changes every {} ms", args.poll_interval);
|
||||
|
@ -122,8 +117,20 @@ fn main() {
|
|||
debug!("Path updated: {:?}", path);
|
||||
}
|
||||
|
||||
// Wait for current child process to exit
|
||||
wait_process(&child_process, kill, args.restart);
|
||||
// We have three scenarios here:
|
||||
//
|
||||
// 1. Make sure the previous run was ended, then run the command again
|
||||
// 2. Just send a specified signal to the child, do nothing more
|
||||
// 3. Send SIGTERM to the child, wait for it to exit, then run the command again
|
||||
// 4. Send a specified signal to the child, wait for it to exit, then run the command again
|
||||
//
|
||||
let scenario = (args.restart, signal.is_some());
|
||||
|
||||
match scenario {
|
||||
// Custom restart behaviour (--restart was given, and --signal specified):
|
||||
// Send specified signal to the child, wait for it to exit, then run the command again
|
||||
(true, true) => {
|
||||
signal_process(&child_process, signal, true);
|
||||
|
||||
// Launch child process
|
||||
if args.clear_screen {
|
||||
|
@ -135,10 +142,51 @@ fn main() {
|
|||
let mut guard = child_process.write().unwrap();
|
||||
*guard = Some(process::spawn(&args.cmd, paths));
|
||||
}
|
||||
}
|
||||
|
||||
// Default restart behaviour (--restart was given, but --signal wasn't specified):
|
||||
// Send SIGTERM to the child, wait for it to exit, then run the command again
|
||||
(true, false) => {
|
||||
let sigterm = signal::new(Some("SIGTERM".to_owned()));
|
||||
signal_process(&child_process, sigterm, true);
|
||||
|
||||
// Launch child process
|
||||
if args.clear_screen {
|
||||
cli::clear_screen();
|
||||
}
|
||||
|
||||
debug!("Launching child process");
|
||||
{
|
||||
let mut guard = child_process.write().unwrap();
|
||||
*guard = Some(process::spawn(&args.cmd, paths));
|
||||
}
|
||||
}
|
||||
|
||||
// SIGHUP scenario: --signal was given, but --restart was not
|
||||
// Just send a signal (e.g. SIGHUP) to the child, do nothing more
|
||||
(false, true) => signal_process(&child_process, signal, false),
|
||||
|
||||
// Default behaviour (neither --signal nor --restart specified):
|
||||
// Make sure the previous run was ended, then run the command again
|
||||
(false, false) => {
|
||||
signal_process(&child_process, None, true);
|
||||
|
||||
// Launch child process
|
||||
if args.clear_screen {
|
||||
cli::clear_screen();
|
||||
}
|
||||
|
||||
debug!("Launching child process");
|
||||
{
|
||||
let mut guard = child_process.write().unwrap();
|
||||
*guard = Some(process::spawn(&args.cmd, paths));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle once option for integration testing
|
||||
if args.once {
|
||||
wait_process(&child_process, kill, false);
|
||||
signal_process(&child_process, signal, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -188,20 +236,18 @@ fn wait_fs(rx: &Receiver<Event>, filter: &NotificationFilter) -> Vec<PathBuf> {
|
|||
paths
|
||||
}
|
||||
|
||||
fn wait_process(process: &RwLock<Option<Process>>, kill: bool, restart: bool) {
|
||||
// signal_process sends signal to process. It waits for the process to exit if wait is true
|
||||
fn signal_process(process: &RwLock<Option<Process>>, signal: Option<Signal>, wait: bool) {
|
||||
let guard = process.read().unwrap();
|
||||
|
||||
if let Some(ref child) = *guard {
|
||||
if restart {
|
||||
debug!("Stopping child process");
|
||||
if kill {
|
||||
child.kill();
|
||||
} else {
|
||||
child.terminate();
|
||||
}
|
||||
if let Some(s) = signal {
|
||||
child.signal(s);
|
||||
}
|
||||
|
||||
if wait {
|
||||
debug!("Waiting for process to exit...");
|
||||
child.wait();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ mod imp {
|
|||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
use std::sync::*;
|
||||
use signal::Signal;
|
||||
|
||||
pub struct Process {
|
||||
pgid: pid_t,
|
||||
|
@ -40,7 +41,8 @@ mod imp {
|
|||
}
|
||||
|
||||
// Until process_exec lands in stable, handle fork/exec ourselves
|
||||
command.before_exec(|| setpgid(0, 0).map_err(io::Error::from))
|
||||
command
|
||||
.before_exec(|| setpgid(0, 0).map_err(io::Error::from))
|
||||
.spawn()
|
||||
.and_then(|p| {
|
||||
Ok(Process {
|
||||
|
@ -51,14 +53,6 @@ mod imp {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn kill(&self) {
|
||||
self.signal(SIGKILL);
|
||||
}
|
||||
|
||||
pub fn pause(&self) {
|
||||
self.signal(SIGTSTP);
|
||||
}
|
||||
|
||||
pub fn reap(&self) {
|
||||
use nix::sys::wait::*;
|
||||
|
||||
|
@ -82,11 +76,15 @@ mod imp {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn resume(&self) {
|
||||
self.signal(SIGCONT);
|
||||
pub fn signal(&self, signal: Signal) {
|
||||
use signal::ConvertToLibc;
|
||||
|
||||
let signo = signal.convert_to_libc();
|
||||
debug!("Sending {:?} (int: {}) to child process", signal, signo);
|
||||
self.c_signal(signo);
|
||||
}
|
||||
|
||||
fn signal(&self, sig: c_int) {
|
||||
fn c_signal(&self, sig: c_int) {
|
||||
extern "C" {
|
||||
fn killpg(pgrp: pid_t, sig: c_int) -> c_int;
|
||||
}
|
||||
|
@ -97,10 +95,6 @@ mod imp {
|
|||
|
||||
}
|
||||
|
||||
pub fn terminate(&self) {
|
||||
self.signal(SIGTERM);
|
||||
}
|
||||
|
||||
pub fn wait(&self) {
|
||||
let mut done = self.lock.lock().unwrap();
|
||||
while !*done {
|
||||
|
@ -119,6 +113,7 @@ mod imp {
|
|||
use std::process::Command;
|
||||
use kernel32::*;
|
||||
use winapi::*;
|
||||
use signal::Signal;
|
||||
|
||||
pub struct Process {
|
||||
job: HANDLE,
|
||||
|
@ -160,7 +155,9 @@ mod imp {
|
|||
command.env("WATCHEXEC_COMMON_PATH", common_path);
|
||||
}
|
||||
|
||||
command.spawn().and_then(|p| {
|
||||
command
|
||||
.spawn()
|
||||
.and_then(|p| {
|
||||
let r = unsafe { AssignProcessToJobObject(job, p.into_raw_handle()) };
|
||||
if r == 0 {
|
||||
panic!("failed to add to job object: {}", last_err());
|
||||
|
@ -170,17 +167,10 @@ mod imp {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn kill(&self) {
|
||||
self.terminate();
|
||||
}
|
||||
|
||||
pub fn pause(&self) {}
|
||||
|
||||
pub fn reap(&self) {}
|
||||
|
||||
pub fn resume(&self) {}
|
||||
|
||||
pub fn terminate(&self) {
|
||||
pub fn signal(&self, signal: Signal) {
|
||||
debug!("Ignoring signal {:?} (not supported by Windows)", signal);
|
||||
unsafe {
|
||||
let _ = TerminateJobObject(self.job, 1);
|
||||
}
|
||||
|
|
101
src/signal.rs
101
src/signal.rs
|
@ -4,12 +4,70 @@ lazy_static! {
|
|||
static ref CLEANUP: Mutex<Option<Box<Fn(self::Signal) + Send>>> = Mutex::new(None);
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[cfg(unix)]
|
||||
pub use nix::sys::signal::Signal;
|
||||
|
||||
// This is a dummy enum for Windows
|
||||
#[cfg(windows)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum Signal {
|
||||
Terminate,
|
||||
Stop,
|
||||
Continue,
|
||||
ChildExit,
|
||||
SIGKILL,
|
||||
SIGTERM,
|
||||
SIGINT,
|
||||
SIGHUP,
|
||||
SIGSTOP,
|
||||
SIGCONT,
|
||||
SIGCHLD,
|
||||
SIGUSR1,
|
||||
SIGUSR2,
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
use libc::*;
|
||||
|
||||
#[cfg(unix)]
|
||||
pub trait ConvertToLibc {
|
||||
fn convert_to_libc(self) -> c_int;
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
impl ConvertToLibc for Signal {
|
||||
fn convert_to_libc(self) -> c_int {
|
||||
// Convert from signal::Signal enum to libc::* c_int constants
|
||||
match self {
|
||||
Signal::SIGKILL => SIGKILL,
|
||||
Signal::SIGTERM => SIGTERM,
|
||||
Signal::SIGINT => SIGINT,
|
||||
Signal::SIGHUP => SIGHUP,
|
||||
Signal::SIGSTOP => SIGSTOP,
|
||||
Signal::SIGCONT => SIGCONT,
|
||||
Signal::SIGCHLD => SIGCHLD,
|
||||
Signal::SIGUSR1 => SIGUSR1,
|
||||
Signal::SIGUSR2 => SIGUSR2,
|
||||
_ => panic!("unsupported signal: {:?}", self),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(signal_name: Option<String>) -> Option<Signal> {
|
||||
if let Some(signame) = signal_name {
|
||||
let signal = match signame.as_ref() {
|
||||
"SIGKILL" | "KILL" => Signal::SIGKILL,
|
||||
"SIGTERM" | "TERM" => Signal::SIGTERM,
|
||||
"SIGINT" | "INT" => Signal::SIGINT,
|
||||
"SIGHUP" | "HUP" => Signal::SIGHUP,
|
||||
"SIGSTOP" | "STOP" => Signal::SIGSTOP,
|
||||
"SIGCONT" | "CONT" => Signal::SIGCONT,
|
||||
"SIGCHLD" | "CHLD" => Signal::SIGCHLD,
|
||||
"SIGUSR1" | "USR1" => Signal::SIGUSR1,
|
||||
"SIGUSR2" | "USR2" => Signal::SIGUSR2,
|
||||
_ => panic!("unsupported signal: {}", signame),
|
||||
};
|
||||
|
||||
Some(signal)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
|
@ -23,12 +81,17 @@ pub fn install_handler<F>(handler: F)
|
|||
// Mask all signals interesting to us. The mask propagates
|
||||
// to all threads started after this point.
|
||||
let mut mask = SigSet::empty();
|
||||
mask.add(SIGKILL);
|
||||
mask.add(SIGTERM);
|
||||
mask.add(SIGINT);
|
||||
mask.add(SIGTSTP);
|
||||
mask.add(SIGHUP);
|
||||
mask.add(SIGSTOP);
|
||||
mask.add(SIGCONT);
|
||||
mask.add(SIGCHLD);
|
||||
mask.thread_set_mask().expect("unable to set signal mask");
|
||||
mask.add(SIGUSR1);
|
||||
mask.add(SIGUSR2);
|
||||
mask.thread_set_mask()
|
||||
.expect("unable to set signal mask");
|
||||
|
||||
set_handler(handler);
|
||||
|
||||
|
@ -45,36 +108,28 @@ pub fn install_handler<F>(handler: F)
|
|||
// Spawn a thread to catch these signals
|
||||
thread::spawn(move || {
|
||||
loop {
|
||||
let raw_signal = mask.wait().expect("unable to sigwait");
|
||||
debug!("Received {:?}", raw_signal);
|
||||
|
||||
let sig = match raw_signal {
|
||||
SIGTERM | SIGINT => self::Signal::Terminate,
|
||||
SIGTSTP => self::Signal::Stop,
|
||||
SIGCONT => self::Signal::Continue,
|
||||
SIGCHLD => self::Signal::ChildExit,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let signal = mask.wait().expect("Unable to sigwait");
|
||||
debug!("Received {:?}", signal);
|
||||
|
||||
// Invoke closure
|
||||
invoke(sig);
|
||||
invoke(signal);
|
||||
|
||||
// Restore default behavior for received signal and unmask it
|
||||
if raw_signal != SIGCHLD {
|
||||
if signal != SIGCHLD {
|
||||
let default_action =
|
||||
SigAction::new(SigHandler::SigDfl, SaFlags::empty(), SigSet::empty());
|
||||
|
||||
unsafe {
|
||||
let _ = sigaction(raw_signal, &default_action);
|
||||
let _ = sigaction(signal, &default_action);
|
||||
}
|
||||
}
|
||||
|
||||
let mut new_mask = SigSet::empty();
|
||||
new_mask.add(raw_signal);
|
||||
new_mask.add(signal);
|
||||
|
||||
// Re-raise with signal unmasked
|
||||
let _ = new_mask.thread_unblock();
|
||||
let _ = raise(raw_signal);
|
||||
let _ = raise(signal);
|
||||
let _ = new_mask.thread_block();
|
||||
}
|
||||
});
|
||||
|
@ -88,7 +143,7 @@ pub fn install_handler<F>(handler: F)
|
|||
use winapi::{BOOL, DWORD, FALSE, TRUE};
|
||||
|
||||
pub unsafe extern "system" fn ctrl_handler(_: DWORD) -> BOOL {
|
||||
invoke(self::Signal::Terminate);
|
||||
invoke(self::Signal::SIGTERM);
|
||||
|
||||
FALSE
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue