brk_exit/
lib.rs

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