1#![doc = include_str!("../README.md")]
2
3use std::{
4 process::exit,
5 sync::{
6 Arc,
7 atomic::{AtomicBool, Ordering},
8 },
9 thread::sleep,
10 time::Duration,
11};
12
13use log::info;
14
15#[derive(Default, Clone)]
16pub struct Exit {
17 blocking: Arc<AtomicBool>,
18 triggered: Arc<AtomicBool>,
19}
20
21impl Exit {
22 pub fn new() -> Self {
23 let s = Self {
24 triggered: Arc::new(AtomicBool::new(false)),
25 blocking: Arc::new(AtomicBool::new(false)),
26 };
27
28 let triggered = s.triggered.clone();
29
30 let blocking = s.blocking.clone();
31 let is_blocking = move || blocking.load(Ordering::SeqCst);
32
33 ctrlc::set_handler(move || {
34 info!("Exitting...");
35
36 triggered.store(true, Ordering::SeqCst);
37
38 if is_blocking() {
39 info!("Waiting to exit safely...");
40
41 while is_blocking() {
42 sleep(Duration::from_millis(50));
43 }
44 }
45
46 exit(0);
47 })
48 .expect("Error setting Ctrl-C handler");
49
50 s
51 }
52
53 pub fn block(&self) {
54 self.blocking.store(true, Ordering::SeqCst);
55 }
56
57 pub fn release(&self) {
58 self.blocking.store(false, Ordering::SeqCst);
59 }
60
61 pub fn triggered(&self) -> bool {
62 self.triggered.load(Ordering::SeqCst)
63 }
64}