1#![cfg_attr(docsrs, feature(doc_cfg))]
2
3use core::time::Duration;
4use std::sync::atomic::{AtomicBool, AtomicU16, Ordering};
5use std::{io, process, thread};
6
7static INITED: AtomicBool = AtomicBool::new(false);
8static EXITING: AtomicBool = AtomicBool::new(false);
9static EXIT_TIME: AtomicU16 = AtomicU16::new(0);
10#[cfg(feature = "async")]
11static EVENT: event_listener::Event = event_listener::Event::new();
12
13pub fn exit(code: i32) -> ! {
14 EXITING.store(true, Ordering::SeqCst);
15 #[cfg(feature = "async")]
16 EVENT.notify(usize::MAX);
17
18 let exit_time = EXIT_TIME.load(Ordering::SeqCst);
19 thread::sleep(Duration::from_millis(exit_time as u64));
20 process::exit(code);
21}
22pub fn send_exit_signal(code: i32) {
23 thread::Builder::new()
24 .name("will_exit".to_string())
25 .spawn(move || exit(code))
26 .unwrap();
27}
28
29pub fn will_exit() -> bool {
30 EXITING.load(Ordering::Acquire)
31}
32#[cfg(feature = "async")]
33#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
34pub async fn wait_will_exit() {
35 while EXITING.load(Ordering::Acquire) == false {
36 EVENT.listen().await
37 }
38}
39
40pub fn init(exit_time: u16) -> Result<(), io::Error> {
42 EXIT_TIME.store(exit_time, Ordering::SeqCst);
43 let result = INITED.compare_exchange(false, true, Ordering::AcqRel, Ordering::Acquire);
44 if result.is_ok() {
45 unsafe {
46 signal_hook_registry::register(libc::SIGINT, || send_exit_signal(libc::SIGINT))?;
47 signal_hook_registry::register(libc::SIGTERM, || send_exit_signal(libc::SIGTERM))?;
48 signal_hook_registry::register(libc::SIGABRT, || send_exit_signal(libc::SIGABRT))?;
49 #[cfg(not(windows))]
50 signal_hook_registry::register(libc::SIGQUIT, || send_exit_signal(libc::SIGQUIT))?;
51 }
52 }
53 Ok(())
54}