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 {
|
||||
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));
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,11 +59,13 @@ pub fn install_handler<F>(handler: F)
|
|||
invoke(sig);
|
||||
|
||||
// Restore default behavior for received signal and unmask it
|
||||
if raw_signal != SIGCHLD {
|
||||
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);
|
||||
|
|
Loading…
Reference in New Issue