leo_lang/cli/commands/devnet/
shutdown.rs1use crossbeam_channel::Sender;
18use std::{io, thread};
19
20pub fn install_shutdown_listener(tx: Sender<()>) -> io::Result<thread::JoinHandle<()>> {
21 #[cfg(unix)]
22 {
23 unix::install(tx)
24 }
25
26 #[cfg(windows)]
27 {
28 windows::install(tx)
29 }
30}
31
32#[cfg(unix)]
33mod unix {
34 use super::*;
35 use signal_hook::{consts::signal::*, iterator::Signals};
36
37 pub fn install(tx: Sender<()>) -> io::Result<thread::JoinHandle<()>> {
38 let mut signals = Signals::new([SIGINT, SIGTERM, SIGQUIT, SIGHUP])?;
39
40 Ok(thread::spawn(move || {
41 for _sig in signals.forever() {
42 let _ = tx.try_send(());
43 }
44 }))
45 }
46}
47
48#[cfg(windows)]
49mod windows {
50 use super::*;
51 use once_cell::sync::OnceCell;
52 use windows_sys::Win32::System::Console::{
53 CTRL_BREAK_EVENT,
54 CTRL_C_EVENT,
55 CTRL_CLOSE_EVENT,
56 CTRL_LOGOFF_EVENT,
57 CTRL_SHUTDOWN_EVENT,
58 SetConsoleCtrlHandler,
59 };
60
61 static TX_SLOT: OnceCell<Sender<()>> = OnceCell::new();
63
64 pub fn install(tx: Sender<()>) -> io::Result<thread::JoinHandle<()>> {
65 ctrlc::set_handler({
67 let tx = tx.clone();
68 move || {
69 let _ = tx.try_send(());
70 }
71 })
72 .map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string()))?;
73
74 enable_console_close_handler(tx)?;
76
77 Ok(std::thread::spawn(|| {
79 loop {
80 std::thread::park();
81 }
82 }))
83 }
84
85 fn enable_console_close_handler(tx: Sender<()>) -> io::Result<()> {
86 let _ = TX_SLOT.set(tx);
88
89 #[allow(unsafe_code)]
91 unsafe extern "system" fn handler(ctrl: u32) -> i32 {
92 match ctrl {
93 CTRL_C_EVENT | CTRL_BREAK_EVENT | CTRL_CLOSE_EVENT | CTRL_LOGOFF_EVENT | CTRL_SHUTDOWN_EVENT => {
94 if let Some(tx) = TX_SLOT.get() {
95 let _ = tx.try_send(());
96 }
97 1 }
99 _ => 0, }
101 }
102
103 #[allow(unsafe_code)]
104 unsafe {
105 if SetConsoleCtrlHandler(Some(handler), 1) == 0 {
106 return Err(io::Error::new(io::ErrorKind::Other, "SetConsoleCtrlHandler failed"));
107 }
108 }
109 Ok(())
110 }
111}