1use parking_lot::Mutex;
2use std::cell::RefCell;
3
4use crate::System;
5
6thread_local! {
7 static HANDLERS: RefCell<Vec<oneshot::Sender<Signal>>> = RefCell::default();
8}
9
10static CUR_SYS: Mutex<RefCell<Option<System>>> = Mutex::new(RefCell::new(None));
11
12#[derive(PartialEq, Eq, Clone, Copy, Debug)]
14pub enum Signal {
15 Hup,
17 Int,
19 Term,
21 Quit,
23}
24
25pub fn signal() -> oneshot::Receiver<Signal> {
27 let (tx, rx) = oneshot::channel();
28 System::current().handle().spawn(async move {
29 HANDLERS.with(|handlers| {
30 handlers.borrow_mut().push(tx);
31 });
32 });
33
34 rx
35}
36
37fn register_system(sys: &System) -> bool {
38 if sys.signals_disabled() {
39 true
40 } else {
41 let guard = CUR_SYS.lock();
42
43 let mut store = guard.borrow_mut();
44 let started = store.is_some();
45 *store = Some(sys.clone());
46 started
47 }
48}
49
50fn handle_signal(sig: Signal) {
51 let guard = CUR_SYS.lock();
52 if let Some(sys) = &*guard.borrow() {
53 sys.handle().spawn(async move {
54 HANDLERS.with(|handlers| {
55 for tx in handlers.borrow_mut().drain(..) {
56 let _ = tx.send(sig);
57 }
58 });
59 });
60 }
61}
62
63#[cfg(target_family = "unix")]
64pub(crate) fn start(sys: &System) {
69 if !register_system(sys) {
70 use signal_hook::consts::signal::{SIGHUP, SIGINT, SIGQUIT, SIGTERM, SIGUSR2};
71 use signal_hook::low_level::register;
72
73 for (s, sig) in [
74 (SIGHUP, Signal::Hup),
75 (SIGINT, Signal::Int),
76 (SIGTERM, Signal::Term),
77 (SIGQUIT, Signal::Quit),
78 ] {
79 let _ = unsafe { register(s, move || handle_signal(sig)) };
80 }
81
82 let _ = unsafe { register(SIGUSR2, || crate::system::sig_usr2()) };
83 }
84}
85
86#[cfg(target_family = "windows")]
87pub(crate) fn start(sys: &System) {
92 if !register_system(sys) {
93 let _ = std::thread::Builder::new()
94 .name("ntex signals".to_string())
95 .spawn(move || {
96 ctrlc::set_handler(move || handle_signal(Signal::Int))
97 .expect("Error setting Ctrl-C handler");
98 });
99 }
100}