2019-04-11 15:23:14 -07:00
|
|
|
use crate::common::*;
|
2018-08-27 16:03:52 -07:00
|
|
|
|
|
|
|
pub struct InterruptHandler {
|
|
|
|
blocks: u32,
|
|
|
|
interrupted: bool,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl InterruptHandler {
|
|
|
|
pub fn install() -> Result<(), ctrlc::Error> {
|
|
|
|
ctrlc::set_handler(|| InterruptHandler::instance().interrupt())
|
|
|
|
}
|
|
|
|
|
2019-04-15 22:40:02 -07:00
|
|
|
pub fn instance() -> MutexGuard<'static, InterruptHandler> {
|
2018-08-27 16:03:52 -07:00
|
|
|
lazy_static! {
|
|
|
|
static ref INSTANCE: Mutex<InterruptHandler> = Mutex::new(InterruptHandler::new());
|
|
|
|
}
|
|
|
|
|
|
|
|
match INSTANCE.lock() {
|
|
|
|
Ok(guard) => guard,
|
|
|
|
Err(poison_error) => die!(
|
|
|
|
"{}",
|
|
|
|
RuntimeError::Internal {
|
|
|
|
message: format!("interrupt handler mutex poisoned: {}", poison_error),
|
|
|
|
}
|
|
|
|
),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn new() -> InterruptHandler {
|
|
|
|
InterruptHandler {
|
|
|
|
blocks: 0,
|
|
|
|
interrupted: false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn interrupt(&mut self) {
|
|
|
|
self.interrupted = true;
|
|
|
|
|
|
|
|
if self.blocks > 0 {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Self::exit();
|
|
|
|
}
|
|
|
|
|
|
|
|
fn exit() {
|
|
|
|
process::exit(130);
|
|
|
|
}
|
|
|
|
|
2019-04-15 22:40:02 -07:00
|
|
|
pub fn block(&mut self) {
|
2018-08-27 16:03:52 -07:00
|
|
|
self.blocks += 1;
|
|
|
|
}
|
|
|
|
|
2019-04-15 22:40:02 -07:00
|
|
|
pub fn unblock(&mut self) {
|
2018-08-27 16:03:52 -07:00
|
|
|
if self.blocks == 0 {
|
|
|
|
die!(
|
|
|
|
"{}",
|
|
|
|
RuntimeError::Internal {
|
|
|
|
message: "attempted to unblock interrupt handler, but handler was not blocked"
|
|
|
|
.to_string(),
|
|
|
|
}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
self.blocks -= 1;
|
|
|
|
|
|
|
|
if self.interrupted {
|
|
|
|
Self::exit();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn guard<T, F: FnOnce() -> T>(function: F) -> T {
|
|
|
|
let _guard = InterruptGuard::new();
|
|
|
|
function()
|
|
|
|
}
|
|
|
|
}
|