Cleanup, initial Windows implementation of interrupt handler

This commit is contained in:
Matt Green 2016-11-09 17:00:24 -05:00
parent cf0a98b7a5
commit 6523f6edf5
2 changed files with 34 additions and 14 deletions

View File

@ -1,3 +1,9 @@
use std::sync::Mutex;
lazy_static! {
static ref CLEANUP: Mutex<Option<Box<Fn() + Send>>> = Mutex::new(None);
}
#[cfg(unix)] #[cfg(unix)]
pub fn install_handler<F>(handler: F) pub fn install_handler<F>(handler: F)
where F: Fn() + 'static + Send + Sync { where F: Fn() + 'static + Send + Sync {
@ -12,12 +18,14 @@ pub fn install_handler<F>(handler: F)
mask.add(SIGINT); mask.add(SIGINT);
mask.thread_set_mask().expect("unable to set signal mask"); mask.thread_set_mask().expect("unable to set signal mask");
set_handler(handler);
// Spawn a thread to catch these signals // Spawn a thread to catch these signals
thread::spawn(move || { thread::spawn(move || {
let sig = mask.wait().expect("unable to sigwait"); let sig = mask.wait().expect("unable to sigwait");
// Invoke closure // Invoke closure
handler(); invoke();
// Restore default behavior for received signal and unmask it // Restore default behavior for received signal and unmask it
unsafe { unsafe {
@ -33,22 +41,34 @@ pub fn install_handler<F>(handler: F)
}); });
} }
/// On Windows, use SetConsoleCtrlHandler() to send an interrupt
/// SetConsoleCtrlHandler runs in it's own thread, so it's safe.
#[cfg(windows)] #[cfg(windows)]
pub fn install() -> Receiver<()> { pub fn install_handler<F>(handler: F)
where F: Fn() + 'static + Send + Sync {
use kernel32::SetConsoleCtrlHandler; use kernel32::SetConsoleCtrlHandler;
use winapi::{BOOL, DWORD, TRUE}; use winapi::{BOOL, DWORD, FALSE};
pub unsafe extern "system" fn ctrl_handler(_: DWORD) -> BOOL { pub unsafe extern "system" fn ctrl_handler(_: DWORD) -> BOOL {
let _ = send_interrupt(); invoke();
TRUE
FALSE
} }
let rx = create_channel(); set_handler(handler);
unsafe { unsafe {
SetConsoleCtrlHandler(Some(ctrl_handler), TRUE); SetConsoleCtrlHandler(Some(ctrl_handler), TRUE);
} }
}
rx
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));
} }

View File

@ -80,8 +80,8 @@ fn init_logger(debug: bool) {
fn main() { 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 || { interrupt::install_handler(move || {
if let Some(lock) = weak_child.upgrade() { if let Some(lock) = weak_child.upgrade() {
let strong = lock.read().unwrap(); let strong = lock.read().unwrap();
@ -147,7 +147,7 @@ fn main() {
debug!("Path updated: {:?}", path); debug!("Path updated: {:?}", path);
} }
//. Wait for current child process to exit // Wait for current child process to exit
{ {
let guard = child_process.read().unwrap(); let guard = child_process.read().unwrap();
@ -168,8 +168,8 @@ fn main() {
} }
{ {
let mut lock = child_process.write().unwrap(); let mut guard = child_process.write().unwrap();
*lock = Process::new(&args.cmd, paths).ok(); *guard = Process::new(&args.cmd, paths).ok();
} }
} }
} }