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}