1#![allow(static_mut_refs)]
2use std::{cell::RefCell, future::poll_fn, sync::Arc, task::Poll};
3
4use atomic_waker::AtomicWaker;
5
6use crate::System;
7
8thread_local! {
9 static STOP: RefCell<Option<oneshot::Sender<()>>> = const { RefCell::new(None) };
10 static HANDLERS: RefCell<Vec<oneshot::Sender<Arc<[Signal]>>>> = RefCell::default();
11}
12
13static mut CUR_SYS: Option<System> = None;
14static mut SIGS: [Option<Signal>; 10] = [None; 10];
15static HND_WAKER: AtomicWaker = AtomicWaker::new();
16
17#[derive(PartialEq, Eq, Clone, Copy, Debug)]
19pub enum Signal {
20 Hup,
22 Int,
24 Term,
26 Quit,
28 Segv,
30}
31
32pub fn signal() -> oneshot::AsyncReceiver<Arc<[Signal]>> {
37 let (tx, rx) = oneshot::async_channel();
38 System::current().handle().spawn(async move {
39 HANDLERS.with(|handlers| {
40 handlers.borrow_mut().push(tx);
41 });
42 });
43
44 rx
45}
46
47pub fn is_enabled() -> bool {
49 unsafe { CUR_SYS.is_some() }
50}
51
52fn register_system(sys: &System) -> bool {
53 unsafe {
54 if CUR_SYS.is_some() {
55 false
56 } else {
57 CUR_SYS = Some(sys.clone());
58
59 let (tx, rx) = oneshot::async_channel();
60 sys.handle().spawn(signals(rx));
61 STOP.with(|stop| {
62 *stop.borrow_mut() = Some(tx);
63 });
64 true
65 }
66 }
67}
68
69fn unregister_system(sys: &System) -> bool {
70 unsafe {
71 if let Some(cur) = CUR_SYS.take() {
72 if cur.id() == sys.id() {
73 sys.handle().spawn(async move {
74 STOP.with(|stop| {
75 if let Some(tx) = stop.borrow_mut().take() {
76 let _ = tx.send(());
77 }
78 });
79 });
80 true
81 } else {
82 CUR_SYS = Some(cur);
83 false
84 }
85 } else {
86 false
87 }
88 }
89}
90
91fn handle_signal(sig: Signal) {
92 unsafe {
93 for s in &mut SIGS {
94 if s.is_none() {
95 *s = Some(sig);
96 break;
97 }
98 }
99 HND_WAKER.wake();
100 }
101}
102
103#[cfg(target_family = "unix")]
104static mut SIG_HANDLERS: [Option<signal_hook::SigId>; 10] = [None; 10];
105
106#[cfg(target_family = "unix")]
107pub(crate) fn start(sys: &System) {
109 static ONCE: std::sync::Once = std::sync::Once::new();
110
111 if register_system(sys) {
112 use nix::sys::signal;
113 use signal_hook::consts::signal::{SIGHUP, SIGINT, SIGQUIT, SIGTERM, SIGUSR2};
114 use signal_hook::low_level::register;
115
116 ONCE.call_once(|| {
117 let buf = Vec::leak(vec![0u128; 4096]);
119 let stack = libc::stack_t {
120 ss_sp: buf.as_ptr() as *mut libc::c_void,
121 ss_flags: 0,
122 ss_size: std::mem::size_of_val(buf),
123 };
124 let mut old = libc::stack_t {
125 ss_sp: std::ptr::null_mut(),
126 ss_flags: 0,
127 ss_size: 0,
128 };
129 let result = unsafe { libc::sigaltstack(&raw const stack, &raw mut old) };
130 if result != 0 {
131 log::error!("Cannot set signal stack");
132 }
133
134 let sig_action = signal::SigAction::new(
135 signal::SigHandler::Handler(sig_segv),
136 signal::SaFlags::SA_NODEFER | signal::SaFlags::SA_ONSTACK,
137 signal::SigSet::empty(),
138 );
139 unsafe {
140 if signal::sigaction(signal::SIGSEGV, &sig_action).is_err() {
141 log::error!("Cannot install signal handler for SIGSEGV");
142 }
143 if signal::sigaction(signal::SIGABRT, &sig_action).is_err() {
144 log::error!("Cannot install signal handler for SIGABRT");
145 }
146 }
147 });
148
149 for (idx, s, sig) in [
150 (0, SIGHUP, Signal::Hup),
151 (1, SIGINT, Signal::Int),
152 (2, SIGTERM, Signal::Term),
153 (3, SIGQUIT, Signal::Quit),
154 ] {
155 unsafe {
156 match register(s, move || handle_signal(sig)) {
157 Ok(s) => SIG_HANDLERS[idx] = Some(s),
158 Err(e) => {
159 log::error!("Cannot install signal handler for {sig:?} with {e:?}");
160 }
161 }
162 }
163 }
164
165 unsafe {
166 match register(SIGUSR2, || crate::system::sig_usr2()) {
167 Ok(s) => SIG_HANDLERS[5] = Some(s),
168 Err(_) => log::error!("Cannot install signal handler for SIGUSR2"),
169 }
170 }
171 }
172}
173
174#[cfg(target_family = "unix")]
175pub(crate) fn stop(sys: &System) {
177 if unregister_system(sys) {
178 use signal_hook::low_level::unregister;
179
180 unsafe {
181 for sig in &mut SIG_HANDLERS {
182 if let Some(s) = sig.take() {
183 let _ = unregister(s);
184 }
185 }
186 }
187 }
188}
189
190#[cfg(target_family = "windows")]
191pub(crate) fn start(sys: &System) {
196 if register_system(sys) {
197 ctrlc::set_handler(move || handle_signal(Signal::Int))
198 .expect("Error setting Ctrl-C handler");
199 }
200}
201
202#[cfg(target_family = "windows")]
203pub(crate) fn stop(sys: &System) {
205 if unregister_system(sys) {
206 log::info!("Signals handling is disabled");
207 }
208}
209
210async fn signals(rx: oneshot::AsyncReceiver<()>) {
211 let mut rx = std::pin::pin!(rx);
212
213 poll_fn(|cx| {
214 if rx.as_mut().poll(cx).is_ready() {
215 Poll::Ready(())
216 } else {
217 HND_WAKER.register(cx.waker());
218
219 let mut sigs = Vec::new();
220 unsafe {
221 for sig in &mut SIGS {
222 if let Some(sig) = sig.take() {
223 sigs.push(sig);
224 }
225 }
226 }
227 if !sigs.is_empty() {
228 let sigs: Arc<[Signal]> = Arc::from(sigs);
229
230 HANDLERS.with(|handlers| {
231 for tx in handlers.borrow_mut().drain(..) {
232 let _ = tx.send(sigs.clone());
233 }
234 });
235 }
236
237 Poll::Pending
238 }
239 })
240 .await;
241}
242
243#[cfg(target_family = "unix")]
244extern "C" fn sig_segv(_: i32) {
245 eprintln!("Stack Overflow:\n{:?}", backtrace::Backtrace::new());
246 handle_signal(Signal::Segv);
247}