1use std::thread;
2
3use parking_lot::Mutex;
4
5use nix::sys::signal::{SigSet, SigmaskHow, Signal};
6
7use crate::{Error, SigType};
8
9type Callback = dyn FnOnce(SigType) + Send + Sync;
10
11static HANDLER: Mutex<Option<Box<Callback>>> = Mutex::new(None);
12
13
14pub struct KillWait {
16 jh: thread::JoinHandle<()>
17}
18
19impl KillWait {
20 pub fn wait(self) {
25 self.jh.join().unwrap();
26 }
27}
28
29
30pub fn init() -> Result<KillWait, Error> {
45 let mut ss = SigSet::empty();
49 ss.add(Signal::SIGINT);
50 ss.add(Signal::SIGTERM);
51
52 let mut oldset = SigSet::empty();
53 nix::sys::signal::pthread_sigmask(
54 SigmaskHow::SIG_SETMASK,
55 Some(&ss),
56 Some(&mut oldset)
57 )
58 .unwrap();
59
60 let jh = thread::Builder::new()
61 .name("sigmon".into())
62 .spawn(move || {
63 let mask = unsafe {
66 let mut mask: libc::sigset_t = std::mem::zeroed();
67 libc::sigemptyset(&mut mask);
68 libc::sigaddset(&mut mask, libc::SIGINT);
69 libc::sigaddset(&mut mask, libc::SIGTERM);
70 mask
71 };
72
73 loop {
74 let mut sig: libc::c_int = 0;
75 let ret = unsafe { libc::sigwait(&mask, &mut sig) };
76 if ret == 0 {
77 let signal = Signal::try_from(sig).unwrap();
78
79 let Some(handler) = HANDLER.lock().take() else {
80 continue;
83 };
84
85 match signal {
86 Signal::SIGINT => {
87 handler(SigType::Int);
88 break;
89 }
90 Signal::SIGTERM => {
91 handler(SigType::Term);
92 break;
93 }
94 _ => {}
95 }
96 }
97 }
98 })
99 .map_err(|e| {
100 let msg = format!("Unable to spawn signal monitoring thread; {e}");
101 Error::Internal(msg)
102 })?;
103
104
105 Ok(KillWait { jh })
106}
107
108pub fn register(
114 handler: impl FnOnce(SigType) + 'static + Send + Sync
115) -> Result<(), Error> {
116 let mut g = HANDLER.lock();
117 *g = Some(Box::new(handler));
118 drop(g);
119 Ok(())
120}
121
122