SIGCHLD handling

This commit is contained in:
Matt Green 2016-12-20 11:44:18 -05:00
parent a925cb356a
commit b2c809c87a
3 changed files with 59 additions and 17 deletions

View File

@ -95,15 +95,10 @@ fn main() {
} else {
child.terminate();
}
child.wait();
},
Signal::Stop => {
child.pause();
},
Signal::Continue => {
child.resume();
}
Signal::Stop => child.pause(),
Signal::Continue => child.resume(),
Signal::ChildExit => child.reap(),
}
}
}
@ -153,6 +148,7 @@ fn main() {
}
loop {
debug!("Waiting for filesystem activity");
let paths = wait(&rx, &filter);
if let Some(path) = paths.get(0) {
debug!("Path updated: {:?}", path);
@ -182,6 +178,7 @@ fn main() {
cli::clear_screen();
}
debug!("Launching child process");
{
let mut guard = child_process.write().unwrap();
*guard = Some(process::spawn(&args.cmd, paths));

View File

@ -12,9 +12,12 @@ mod imp {
use std::io::Result;
use std::path::PathBuf;
use std::process::Command;
use std::sync::*;
pub struct Process {
pgid: pid_t,
lock: Mutex<bool>,
cvar: Condvar,
}
impl Process {
@ -55,7 +58,11 @@ mod imp {
}
let _ = close(w);
Ok(Process { pgid: child })
Ok(Process {
pgid: child,
lock: Mutex::new(false),
cvar: Condvar::new(),
})
}
Ok(ForkResult::Child) => {
let _ = setpgid(0, 0);
@ -85,6 +92,25 @@ mod imp {
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) {
self.signal(SIGCONT);
@ -106,9 +132,10 @@ mod imp {
}
pub fn wait(&self) {
use nix::sys::wait::waitpid;
while let Ok(_) = waitpid(-self.pgid, None) {}
let mut done = self.lock.lock().unwrap();
while !*done {
done = self.cvar.wait(done).unwrap();
}
}
}
}
@ -181,6 +208,9 @@ mod imp {
pub fn pause(&self) {
}
pub fn reap(&self) {
}
pub fn resume(&self) {
}
@ -190,7 +220,6 @@ mod imp {
}
}
pub fn wait(&self) {
unsafe {
let _ = WaitForSingleObject(self.job, INFINITE);

View File

@ -7,7 +7,8 @@ lazy_static! {
pub enum Signal {
Terminate,
Stop,
Continue
Continue,
ChildExit
}
#[cfg(unix)]
@ -15,6 +16,7 @@ pub fn install_handler<F>(handler: F)
where F: Fn(self::Signal) + 'static + Send + Sync
{
use std::thread;
use libc::c_int;
use nix::sys::signal::*;
// 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(SIGTSTP);
mask.add(SIGCONT);
mask.add(SIGCHLD);
mask.thread_set_mask().expect("unable to set signal mask");
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
thread::spawn(move || {
loop {
let raw_signal = mask.wait().expect("unable to sigwait");
debug!("Received {:?}", raw_signal);
let sig = match raw_signal {
SIGTERM => self::Signal::Terminate,
SIGINT => self::Signal::Terminate,
SIGTSTP => self::Signal::Stop,
SIGCONT => self::Signal::Continue,
SIGCHLD => self::Signal::ChildExit,
_ => unreachable!()
};
@ -45,10 +59,12 @@ pub fn install_handler<F>(handler: F)
invoke(sig);
// 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 {
let _ = sigaction(raw_signal, &default_action);
unsafe {
let _ = sigaction(raw_signal, &default_action);
}
}
let mut new_mask = SigSet::empty();