Skip to main content

ntex_rt/
signals.rs

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/// Different types of process signals
13#[derive(PartialEq, Eq, Clone, Copy, Debug)]
14pub enum Signal {
15    /// SIGHUP
16    Hup,
17    /// SIGINT
18    Int,
19    /// SIGTERM
20    Term,
21    /// SIGQUIT
22    Quit,
23}
24
25/// Register signal handler.
26pub 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")]
64/// Register signal handler.
65///
66/// Signals are handled by oneshots, you have to re-register
67/// after each signal.
68pub(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")]
87/// Register signal handler.
88///
89/// Signals are handled by oneshots, you have to re-register
90/// after each signal.
91pub(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}