pub_just/
interrupt_handler.rs1use super::*;
2
3pub struct InterruptHandler {
4 blocks: u32,
5 interrupted: bool,
6 verbosity: Verbosity,
7}
8
9impl InterruptHandler {
10 pub fn install(verbosity: Verbosity) -> Result<(), ctrlc::Error> {
11 let mut instance = Self::instance();
12 instance.verbosity = verbosity;
13 ctrlc::set_handler(|| Self::instance().interrupt())
14 }
15
16 pub fn instance() -> MutexGuard<'static, Self> {
17 static INSTANCE: Mutex<InterruptHandler> = Mutex::new(InterruptHandler::new());
18
19 match INSTANCE.lock() {
20 Ok(guard) => guard,
21 Err(poison_error) => {
22 eprintln!(
23 "{}",
24 Error::Internal {
25 message: format!("interrupt handler mutex poisoned: {poison_error}"),
26 }
27 .color_display(Color::auto().stderr())
28 );
29 process::exit(EXIT_FAILURE);
30 }
31 }
32 }
33
34 const fn new() -> Self {
35 Self {
36 blocks: 0,
37 interrupted: false,
38 verbosity: Verbosity::default(),
39 }
40 }
41
42 fn interrupt(&mut self) {
43 self.interrupted = true;
44
45 if self.blocks > 0 {
46 return;
47 }
48
49 Self::exit();
50 }
51
52 fn exit() {
53 process::exit(130);
54 }
55
56 pub fn block(&mut self) {
57 self.blocks += 1;
58 }
59
60 pub fn unblock(&mut self) {
61 if self.blocks == 0 {
62 if self.verbosity.loud() {
63 eprintln!(
64 "{}",
65 Error::Internal {
66 message: "attempted to unblock interrupt handler, but handler was not blocked"
67 .to_owned(),
68 }
69 .color_display(Color::auto().stderr())
70 );
71 }
72 process::exit(EXIT_FAILURE);
73 }
74
75 self.blocks -= 1;
76
77 if self.interrupted {
78 Self::exit();
79 }
80 }
81
82 pub fn guard<T, F: FnOnce() -> T>(function: F) -> T {
83 let _guard = InterruptGuard::new();
84 function()
85 }
86}