mirror of
https://github.com/watchexec/watchexec.git
synced 2024-09-29 22:51:33 +02:00
SIGCHLD handling
This commit is contained in:
parent
a925cb356a
commit
b2c809c87a
13
src/main.rs
13
src/main.rs
@ -95,15 +95,10 @@ fn main() {
|
|||||||
} else {
|
} else {
|
||||||
child.terminate();
|
child.terminate();
|
||||||
}
|
}
|
||||||
|
|
||||||
child.wait();
|
|
||||||
},
|
},
|
||||||
Signal::Stop => {
|
Signal::Stop => child.pause(),
|
||||||
child.pause();
|
Signal::Continue => child.resume(),
|
||||||
},
|
Signal::ChildExit => child.reap(),
|
||||||
Signal::Continue => {
|
|
||||||
child.resume();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -153,6 +148,7 @@ fn main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
debug!("Waiting for filesystem activity");
|
||||||
let paths = wait(&rx, &filter);
|
let paths = wait(&rx, &filter);
|
||||||
if let Some(path) = paths.get(0) {
|
if let Some(path) = paths.get(0) {
|
||||||
debug!("Path updated: {:?}", path);
|
debug!("Path updated: {:?}", path);
|
||||||
@ -182,6 +178,7 @@ fn main() {
|
|||||||
cli::clear_screen();
|
cli::clear_screen();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
debug!("Launching child process");
|
||||||
{
|
{
|
||||||
let mut guard = child_process.write().unwrap();
|
let mut guard = child_process.write().unwrap();
|
||||||
*guard = Some(process::spawn(&args.cmd, paths));
|
*guard = Some(process::spawn(&args.cmd, paths));
|
||||||
|
@ -12,9 +12,12 @@ mod imp {
|
|||||||
use std::io::Result;
|
use std::io::Result;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
use std::sync::*;
|
||||||
|
|
||||||
pub struct Process {
|
pub struct Process {
|
||||||
pgid: pid_t,
|
pgid: pid_t,
|
||||||
|
lock: Mutex<bool>,
|
||||||
|
cvar: Condvar,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Process {
|
impl Process {
|
||||||
@ -55,7 +58,11 @@ mod imp {
|
|||||||
}
|
}
|
||||||
let _ = close(w);
|
let _ = close(w);
|
||||||
|
|
||||||
Ok(Process { pgid: child })
|
Ok(Process {
|
||||||
|
pgid: child,
|
||||||
|
lock: Mutex::new(false),
|
||||||
|
cvar: Condvar::new(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
Ok(ForkResult::Child) => {
|
Ok(ForkResult::Child) => {
|
||||||
let _ = setpgid(0, 0);
|
let _ = setpgid(0, 0);
|
||||||
@ -85,6 +92,25 @@ mod imp {
|
|||||||
self.signal(SIGTSTP);
|
self.signal(SIGTSTP);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn reap(&self) {
|
||||||
|
use nix::sys::wait::*;
|
||||||
|
|
||||||
|
let mut finished = true;
|
||||||
|
loop {
|
||||||
|
match waitpid(-self.pgid, Some(WNOHANG)) {
|
||||||
|
Ok(WaitStatus::Exited(_, _)) => finished = finished && true,
|
||||||
|
Ok(WaitStatus::Signaled(_, _, _)) => finished = finished && true,
|
||||||
|
Ok(_) => finished = false,
|
||||||
|
Err(_) => break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if finished {
|
||||||
|
let mut done = self.lock.lock().unwrap();
|
||||||
|
*done = true;
|
||||||
|
self.cvar.notify_one();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn resume(&self) {
|
pub fn resume(&self) {
|
||||||
self.signal(SIGCONT);
|
self.signal(SIGCONT);
|
||||||
@ -106,9 +132,10 @@ mod imp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn wait(&self) {
|
pub fn wait(&self) {
|
||||||
use nix::sys::wait::waitpid;
|
let mut done = self.lock.lock().unwrap();
|
||||||
|
while !*done {
|
||||||
while let Ok(_) = waitpid(-self.pgid, None) {}
|
done = self.cvar.wait(done).unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -181,6 +208,9 @@ mod imp {
|
|||||||
pub fn pause(&self) {
|
pub fn pause(&self) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn reap(&self) {
|
||||||
|
}
|
||||||
|
|
||||||
pub fn resume(&self) {
|
pub fn resume(&self) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -190,7 +220,6 @@ mod imp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn wait(&self) {
|
pub fn wait(&self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let _ = WaitForSingleObject(self.job, INFINITE);
|
let _ = WaitForSingleObject(self.job, INFINITE);
|
||||||
|
@ -7,7 +7,8 @@ lazy_static! {
|
|||||||
pub enum Signal {
|
pub enum Signal {
|
||||||
Terminate,
|
Terminate,
|
||||||
Stop,
|
Stop,
|
||||||
Continue
|
Continue,
|
||||||
|
ChildExit
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
@ -15,6 +16,7 @@ pub fn install_handler<F>(handler: F)
|
|||||||
where F: Fn(self::Signal) + 'static + Send + Sync
|
where F: Fn(self::Signal) + 'static + Send + Sync
|
||||||
{
|
{
|
||||||
use std::thread;
|
use std::thread;
|
||||||
|
use libc::c_int;
|
||||||
use nix::sys::signal::*;
|
use nix::sys::signal::*;
|
||||||
|
|
||||||
// Mask all signals interesting to us. The mask propagates
|
// Mask all signals interesting to us. The mask propagates
|
||||||
@ -24,20 +26,32 @@ pub fn install_handler<F>(handler: F)
|
|||||||
mask.add(SIGINT);
|
mask.add(SIGINT);
|
||||||
mask.add(SIGTSTP);
|
mask.add(SIGTSTP);
|
||||||
mask.add(SIGCONT);
|
mask.add(SIGCONT);
|
||||||
|
mask.add(SIGCHLD);
|
||||||
mask.thread_set_mask().expect("unable to set signal mask");
|
mask.thread_set_mask().expect("unable to set signal mask");
|
||||||
|
|
||||||
set_handler(handler);
|
set_handler(handler);
|
||||||
|
|
||||||
|
// Indicate interest in SIGCHLD by setting a dummy handler
|
||||||
|
pub extern "C" fn sigchld_handler(_: c_int) {
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let _ = sigaction(SIGCHLD, &SigAction::new(
|
||||||
|
SigHandler::Handler(sigchld_handler), SaFlags::empty(), SigSet::empty()));
|
||||||
|
}
|
||||||
|
|
||||||
// Spawn a thread to catch these signals
|
// Spawn a thread to catch these signals
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
loop {
|
loop {
|
||||||
let raw_signal = mask.wait().expect("unable to sigwait");
|
let raw_signal = mask.wait().expect("unable to sigwait");
|
||||||
|
debug!("Received {:?}", raw_signal);
|
||||||
|
|
||||||
let sig = match raw_signal {
|
let sig = match raw_signal {
|
||||||
SIGTERM => self::Signal::Terminate,
|
SIGTERM => self::Signal::Terminate,
|
||||||
SIGINT => self::Signal::Terminate,
|
SIGINT => self::Signal::Terminate,
|
||||||
SIGTSTP => self::Signal::Stop,
|
SIGTSTP => self::Signal::Stop,
|
||||||
SIGCONT => self::Signal::Continue,
|
SIGCONT => self::Signal::Continue,
|
||||||
|
SIGCHLD => self::Signal::ChildExit,
|
||||||
_ => unreachable!()
|
_ => unreachable!()
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -45,10 +59,12 @@ pub fn install_handler<F>(handler: F)
|
|||||||
invoke(sig);
|
invoke(sig);
|
||||||
|
|
||||||
// Restore default behavior for received signal and unmask it
|
// Restore default behavior for received signal and unmask it
|
||||||
let default_action = SigAction::new(SigHandler::SigDfl, SaFlags::empty(), SigSet::empty());
|
if raw_signal != SIGCHLD {
|
||||||
|
let default_action = SigAction::new(SigHandler::SigDfl, SaFlags::empty(), SigSet::empty());
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let _ = sigaction(raw_signal, &default_action);
|
let _ = sigaction(raw_signal, &default_action);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut new_mask = SigSet::empty();
|
let mut new_mask = SigSet::empty();
|
||||||
|
Loading…
Reference in New Issue
Block a user