Propagate SIGTSTP/SIGCONT to children
This commit is contained in:
parent
ef37a9fb97
commit
154c23a5a4
|
@ -1,8 +1,8 @@
|
||||||
[root]
|
[root]
|
||||||
name = "watchexec"
|
name = "watchexec"
|
||||||
version = "1.5.0"
|
version = "1.6.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap 2.19.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"clap 2.19.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
"glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"globset 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"globset 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -12,7 +12,7 @@ dependencies = [
|
||||||
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"mktemp 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"mktemp 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"nix 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"nix 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"notify 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"notify 3.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "2.19.0"
|
version = "2.19.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -225,7 +225,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "notify"
|
name = "notify"
|
||||||
version = "3.0.0"
|
version = "3.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -394,7 +394,7 @@ dependencies = [
|
||||||
"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"
|
"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"
|
||||||
"checksum bytes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c129aff112dcc562970abb69e2508b40850dd24c274761bb50fb8a0067ba6c27"
|
"checksum bytes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c129aff112dcc562970abb69e2508b40850dd24c274761bb50fb8a0067ba6c27"
|
||||||
"checksum cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de1e760d7b6535af4241fca8bd8adf68e2e7edacc6b29f5d399050c5e48cf88c"
|
"checksum cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de1e760d7b6535af4241fca8bd8adf68e2e7edacc6b29f5d399050c5e48cf88c"
|
||||||
"checksum clap 2.19.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef87e92396a3d29bf7e611c8a595be35ae90d9cb844a3571425900eaca4f51c8"
|
"checksum clap 2.19.2 (registry+https://github.com/rust-lang/crates.io-index)" = "305ad043f009db535a110200541d4567b63e172b1fe030313fbb92565da7ed24"
|
||||||
"checksum env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "15abd780e45b3ea4f76b4e9a26ff4843258dd8a3eed2775a0e7368c2e7936c2f"
|
"checksum env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "15abd780e45b3ea4f76b4e9a26ff4843258dd8a3eed2775a0e7368c2e7936c2f"
|
||||||
"checksum filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5363ab8e4139b8568a6237db5248646e5a8a2f89bd5ccb02092182b11fd3e922"
|
"checksum filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5363ab8e4139b8568a6237db5248646e5a8a2f89bd5ccb02092182b11fd3e922"
|
||||||
"checksum fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc484842f1e2884faf56f529f960cc12ad8c71ce96cc7abba0a067c98fee344"
|
"checksum fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc484842f1e2884faf56f529f960cc12ad8c71ce96cc7abba0a067c98fee344"
|
||||||
|
@ -414,7 +414,7 @@ dependencies = [
|
||||||
"checksum net2 0.2.26 (registry+https://github.com/rust-lang/crates.io-index)" = "5edf9cb6be97212423aed9413dd4729d62b370b5e1c571750e882cebbbc1e3e2"
|
"checksum net2 0.2.26 (registry+https://github.com/rust-lang/crates.io-index)" = "5edf9cb6be97212423aed9413dd4729d62b370b5e1c571750e882cebbbc1e3e2"
|
||||||
"checksum nix 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bfb3ddedaa14746434a02041940495bf11325c22f6d36125d3bdd56090d50a79"
|
"checksum nix 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bfb3ddedaa14746434a02041940495bf11325c22f6d36125d3bdd56090d50a79"
|
||||||
"checksum nix 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a0d95c5fa8b641c10ad0b8887454ebaafa3c92b5cd5350f8fc693adafd178e7b"
|
"checksum nix 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a0d95c5fa8b641c10ad0b8887454ebaafa3c92b5cd5350f8fc693adafd178e7b"
|
||||||
"checksum notify 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2a29c8a989715f71d2e8272e335a34e657957040cc4a6ecaab218ab717c05835"
|
"checksum notify 3.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "13fdd4a6894329b193f38f03a88823ce721275fdfdb29820c44a30515033524e"
|
||||||
"checksum rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "2791d88c6defac799c3f20d74f094ca33b9332612d9aef9078519c82e4fe04a5"
|
"checksum rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "2791d88c6defac799c3f20d74f094ca33b9332612d9aef9078519c82e4fe04a5"
|
||||||
"checksum regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)" = "4fd4ace6a8cf7860714a2c2280d6c1f7e6a413486c13298bbc86fd3da019402f"
|
"checksum regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)" = "4fd4ace6a8cf7860714a2c2280d6c1f7e6a413486c13298bbc86fd3da019402f"
|
||||||
"checksum regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f9ec002c35e86791825ed294b50008eea9ddfc8def4420124fbc6b08db834957"
|
"checksum regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f9ec002c35e86791825ed294b50008eea9ddfc8def4420124fbc6b08db834957"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "watchexec"
|
name = "watchexec"
|
||||||
version = "1.5.0"
|
version = "1.6.0"
|
||||||
authors = ["Matt Green <mattgreenrocks@gmail.com>"]
|
authors = ["Matt Green <mattgreenrocks@gmail.com>"]
|
||||||
description = "Executes commands in response to file modifications"
|
description = "Executes commands in response to file modifications"
|
||||||
documentation = "https://github.com/mattgreen/watchexec"
|
documentation = "https://github.com/mattgreen/watchexec"
|
||||||
|
|
|
@ -1,76 +0,0 @@
|
||||||
use std::sync::Mutex;
|
|
||||||
|
|
||||||
lazy_static! {
|
|
||||||
static ref CLEANUP: Mutex<Option<Box<Fn() + Send>>> = Mutex::new(None);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(unix)]
|
|
||||||
pub fn install_handler<F>(handler: F)
|
|
||||||
where F: Fn() + 'static + Send + Sync
|
|
||||||
{
|
|
||||||
use std::thread;
|
|
||||||
use nix::sys::signal::*;
|
|
||||||
|
|
||||||
// Mask all termination signals
|
|
||||||
// These propagate to all threads started after this point
|
|
||||||
let mut mask = SigSet::empty();
|
|
||||||
mask.add(SIGTERM);
|
|
||||||
mask.add(SIGINT);
|
|
||||||
mask.thread_set_mask().expect("unable to set signal mask");
|
|
||||||
|
|
||||||
set_handler(handler);
|
|
||||||
|
|
||||||
// Spawn a thread to catch these signals
|
|
||||||
thread::spawn(move || {
|
|
||||||
let sig = mask.wait().expect("unable to sigwait");
|
|
||||||
|
|
||||||
// Invoke closure
|
|
||||||
invoke();
|
|
||||||
|
|
||||||
// Restore default behavior for received signal and unmask it
|
|
||||||
let default_action = SigAction::new(SigHandler::SigDfl, SaFlags::empty(), SigSet::empty());
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
let _ = sigaction(sig, &default_action);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut new_mask = SigSet::empty();
|
|
||||||
new_mask.add(sig);
|
|
||||||
let _ = new_mask.thread_unblock();
|
|
||||||
|
|
||||||
// Re-raise, killing the process
|
|
||||||
let _ = raise(sig);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(windows)]
|
|
||||||
pub fn install_handler<F>(handler: F)
|
|
||||||
where F: Fn() + 'static + Send + Sync
|
|
||||||
{
|
|
||||||
use kernel32::SetConsoleCtrlHandler;
|
|
||||||
use winapi::{BOOL, DWORD, FALSE, TRUE};
|
|
||||||
|
|
||||||
pub unsafe extern "system" fn ctrl_handler(_: DWORD) -> BOOL {
|
|
||||||
invoke();
|
|
||||||
|
|
||||||
FALSE
|
|
||||||
}
|
|
||||||
|
|
||||||
set_handler(handler);
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
SetConsoleCtrlHandler(Some(ctrl_handler), TRUE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn invoke() {
|
|
||||||
if let Some(ref handler) = *CLEANUP.lock().unwrap() {
|
|
||||||
handler()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_handler<F>(handler: F)
|
|
||||||
where F: Fn() + 'static + Send + Sync
|
|
||||||
{
|
|
||||||
*CLEANUP.lock().unwrap() = Some(Box::new(handler));
|
|
||||||
}
|
|
19
src/main.rs
19
src/main.rs
|
@ -21,9 +21,9 @@ extern crate mktemp;
|
||||||
|
|
||||||
mod cli;
|
mod cli;
|
||||||
mod gitignore;
|
mod gitignore;
|
||||||
mod interrupt;
|
|
||||||
mod notification_filter;
|
mod notification_filter;
|
||||||
mod process;
|
mod process;
|
||||||
|
mod signal;
|
||||||
mod watcher;
|
mod watcher;
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
@ -36,6 +36,7 @@ use std::path::{PathBuf};
|
||||||
|
|
||||||
use notification_filter::NotificationFilter;
|
use notification_filter::NotificationFilter;
|
||||||
use process::Process;
|
use process::Process;
|
||||||
|
use signal::Signal;
|
||||||
use watcher::{Event, Watcher};
|
use watcher::{Event, Watcher};
|
||||||
|
|
||||||
fn find_gitignore(path: &Path) -> Option<PathBuf> {
|
fn find_gitignore(path: &Path) -> Option<PathBuf> {
|
||||||
|
@ -81,12 +82,22 @@ fn main() {
|
||||||
let child_process: Arc<RwLock<Option<Process>>> = Arc::new(RwLock::new(None));
|
let child_process: Arc<RwLock<Option<Process>>> = Arc::new(RwLock::new(None));
|
||||||
let weak_child = Arc::downgrade(&child_process);
|
let weak_child = Arc::downgrade(&child_process);
|
||||||
|
|
||||||
interrupt::install_handler(move || {
|
signal::install_handler(move |sig: Signal| {
|
||||||
if let Some(lock) = weak_child.upgrade() {
|
if let Some(lock) = weak_child.upgrade() {
|
||||||
let strong = lock.read().unwrap();
|
let strong = lock.read().unwrap();
|
||||||
if let Some(ref child) = *strong {
|
if let Some(ref child) = *strong {
|
||||||
child.kill();
|
match sig {
|
||||||
child.wait();
|
Signal::Terminate => {
|
||||||
|
child.kill();
|
||||||
|
child.wait();
|
||||||
|
},
|
||||||
|
Signal::Stop => {
|
||||||
|
child.pause();
|
||||||
|
},
|
||||||
|
Signal::Continue => {
|
||||||
|
child.resume();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -8,6 +8,7 @@ pub use self::imp::Process;
|
||||||
|
|
||||||
#[cfg(target_family = "unix")]
|
#[cfg(target_family = "unix")]
|
||||||
mod imp {
|
mod imp {
|
||||||
|
use libc::c_int;
|
||||||
use libc::pid_t;
|
use libc::pid_t;
|
||||||
use std::io::Result;
|
use std::io::Result;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
@ -79,6 +80,25 @@ mod imp {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn kill(&self) {
|
pub fn kill(&self) {
|
||||||
|
use libc::SIGTERM;
|
||||||
|
|
||||||
|
self.signal(SIGTERM);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pause(&self) {
|
||||||
|
use libc::SIGTSTP;
|
||||||
|
|
||||||
|
self.signal(SIGTSTP);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub fn resume(&self) {
|
||||||
|
use libc::SIGCONT;
|
||||||
|
|
||||||
|
self.signal(SIGCONT);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signal(&self, sig: c_int) {
|
||||||
use libc::*;
|
use libc::*;
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
@ -86,8 +106,9 @@ mod imp {
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
killpg(self.pgid, SIGTERM);
|
killpg(self.pgid, sig);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn wait(&self) {
|
pub fn wait(&self) {
|
||||||
|
@ -165,6 +186,12 @@ mod imp {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn pause(&self) {
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn resume(&self) {
|
||||||
|
}
|
||||||
|
|
||||||
pub fn wait(&self) {
|
pub fn wait(&self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let _ = WaitForSingleObject(self.job, INFINITE);
|
let _ = WaitForSingleObject(self.job, INFINITE);
|
||||||
|
|
|
@ -0,0 +1,94 @@
|
||||||
|
use std::sync::Mutex;
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref CLEANUP: Mutex<Option<Box<Fn(self::Signal) + Send>>> = Mutex::new(None);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Signal {
|
||||||
|
Terminate,
|
||||||
|
Stop,
|
||||||
|
Continue
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
pub fn install_handler<F>(handler: F)
|
||||||
|
where F: Fn(self::Signal) + 'static + Send + Sync
|
||||||
|
{
|
||||||
|
use std::thread;
|
||||||
|
use nix::sys::signal::*;
|
||||||
|
|
||||||
|
// Mask all signals interesting to us. The mask propagates
|
||||||
|
// to all threads started after this point.
|
||||||
|
let mut mask = SigSet::empty();
|
||||||
|
mask.add(SIGTERM);
|
||||||
|
mask.add(SIGINT);
|
||||||
|
mask.add(SIGTSTP);
|
||||||
|
mask.add(SIGCONT);
|
||||||
|
mask.thread_set_mask().expect("unable to set signal mask");
|
||||||
|
|
||||||
|
set_handler(handler);
|
||||||
|
|
||||||
|
// Spawn a thread to catch these signals
|
||||||
|
thread::spawn(move || {
|
||||||
|
loop {
|
||||||
|
let raw_signal = mask.wait().expect("unable to sigwait");
|
||||||
|
|
||||||
|
let sig = match raw_signal {
|
||||||
|
SIGTERM => self::Signal::Terminate,
|
||||||
|
SIGINT => self::Signal::Terminate,
|
||||||
|
SIGTSTP => self::Signal::Stop,
|
||||||
|
SIGCONT => self::Signal::Continue,
|
||||||
|
_ => unreachable!()
|
||||||
|
};
|
||||||
|
|
||||||
|
// Invoke closure
|
||||||
|
invoke(sig);
|
||||||
|
|
||||||
|
// Restore default behavior for received signal and unmask it
|
||||||
|
let default_action = SigAction::new(SigHandler::SigDfl, SaFlags::empty(), SigSet::empty());
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let _ = sigaction(raw_signal, &default_action);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut new_mask = SigSet::empty();
|
||||||
|
new_mask.add(raw_signal);
|
||||||
|
let _ = new_mask.thread_unblock();
|
||||||
|
|
||||||
|
// Re-raise
|
||||||
|
let _ = raise(raw_signal);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
pub fn install_handler<F>(handler: F)
|
||||||
|
where F: Fn(self::Signal) + 'static + Send + Sync
|
||||||
|
{
|
||||||
|
use kernel32::SetConsoleCtrlHandler;
|
||||||
|
use winapi::{BOOL, DWORD, FALSE, TRUE};
|
||||||
|
|
||||||
|
pub unsafe extern "system" fn ctrl_handler(_: DWORD) -> BOOL {
|
||||||
|
invoke(self::Signal::Terminate);
|
||||||
|
|
||||||
|
FALSE
|
||||||
|
}
|
||||||
|
|
||||||
|
set_handler(handler);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
SetConsoleCtrlHandler(Some(ctrl_handler), TRUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn invoke(sig: self::Signal) {
|
||||||
|
if let Some(ref handler) = *CLEANUP.lock().unwrap() {
|
||||||
|
handler(sig)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_handler<F>(handler: F)
|
||||||
|
where F: Fn(self::Signal) + 'static + Send + Sync
|
||||||
|
{
|
||||||
|
*CLEANUP.lock().unwrap() = Some(Box::new(handler));
|
||||||
|
}
|
Loading…
Reference in New Issue