watchexec/src/interrupt_handler.rs

70 lines
1.6 KiB
Rust
Raw Normal View History

2016-10-22 21:37:03 +02:00
use std::sync::Mutex;
use std::sync::mpsc::{channel, Receiver, Sender, SendError};
lazy_static! {
static ref INTERRUPT_TX: Mutex<Option<Sender<()>>> = Mutex::new(None);
}
/// On Unix platforms, spawn a thread and use the signal crate
/// to relay signals back to the main thread.
#[cfg(unix)]
pub fn install() -> Receiver<()> {
use std::thread;
use nix::sys::signal::{SIGTERM, SIGINT};
use signal::trap::Trap;
let trap = Trap::trap(&[SIGTERM, SIGINT]);
let rx = create_channel();
thread::spawn(move || {
for _ in trap {
let result = send_interrupt();
if result.is_err() {
break;
}
}
});
rx
}
/// On Windows, use SetConsoleCtrlHandler() to send an interrupt
/// SetConsoleCtrlHandler runs in it's own thread, so it's safe.
#[cfg(windows)]
pub fn install() -> Receiver<()> {
use kernel32::SetConsoleCtrlHandler;
2016-10-22 21:51:17 +02:00
use winapi::{BOOL, DWORD, TRUE};
2016-10-22 21:37:03 +02:00
pub unsafe extern "system" fn ctrl_handler(_: DWORD) -> BOOL {
send_interrupt();
2016-10-22 21:51:17 +02:00
TRUE
2016-10-22 21:37:03 +02:00
}
let rx = create_channel();
2016-10-22 21:51:17 +02:00
unsafe {
SetConsoleCtrlHandler(Some(ctrl_handler), TRUE);
}
2016-10-22 21:37:03 +02:00
rx
}
fn create_channel() -> Receiver<()> {
let mut guard = INTERRUPT_TX.lock().unwrap();
if (*guard).is_some() {
panic!("interrupt_handler::install() already called!");
}
let (tx, rx) = channel();
(*guard) = Some(tx);
rx
}
fn send_interrupt() -> Result<(), SendError<()>> {
if let Some(ref mut tx) = *INTERRUPT_TX.lock().unwrap() {
tx.send(())
} else {
Err(SendError(()))
}
}