1use signal_hook as sigs;
3use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
4use std::sync::Arc;
5use std::time::SystemTime;
6
7pub const SIG_FAST_SHUTDOWN: i32 = sigs::consts::SIGTERM;
8pub const SIG_GRACEFUL_SHUTDOWN: i32 = sigs::consts::SIGINT;
9pub const SIG_RELOAD: i32 = sigs::consts::SIGHUP;
10
11#[derive(Debug, Clone)]
22pub struct SignalTracker {
23 graceful_shutdown: Arc<AtomicBool>,
24 fast_shutdown: Arc<AtomicBool>,
25 reload: Arc<AtomicBool>,
26 reload_request_time: Arc<AtomicU64>,
27 usr1_is_set: Arc<AtomicBool>,
28 usr2_is_set: Arc<AtomicBool>,
29
30 graceful_shutdown_tracked: bool,
32 fast_shutdown_tracked: bool,
33 reload_tracked: bool,
34 usr1_tracked: bool,
35 usr2_tracked: bool,
36}
37
38impl Default for SignalTracker {
39 fn default() -> Self {
40 Self::new()
41 }
42}
43
44impl SignalTracker {
45 pub fn new() -> SignalTracker {
46 SignalTracker {
47 graceful_shutdown: Arc::new(AtomicBool::new(false)),
48 fast_shutdown: Arc::new(AtomicBool::new(false)),
49 reload: Arc::new(AtomicBool::new(false)),
50 reload_request_time: Arc::new(AtomicU64::new(0)),
51 graceful_shutdown_tracked: false,
52 fast_shutdown_tracked: false,
53 reload_tracked: false,
54 usr1_is_set: Arc::new(AtomicBool::new(false)),
55 usr2_is_set: Arc::new(AtomicBool::new(false)),
56 usr1_tracked: false,
57 usr2_tracked: false,
58 }
59 }
60
61 pub fn request_graceful_shutdown(&self) {
63 self.graceful_shutdown.store(true, Ordering::Relaxed);
64 }
65
66 pub fn request_fast_shutdown(&self) {
68 self.fast_shutdown.store(true, Ordering::Relaxed);
69 }
70
71 pub fn request_reload(&self) {
73 self.reload.store(true, Ordering::Relaxed);
74 }
75
76 pub fn any_shutdown_requested(&self) -> bool {
78 self.graceful_shutdown_requested() || self.fast_shutdown_requested()
79 }
80
81 pub fn track_usr1(&mut self) {
82 if self.usr1_tracked {
83 log::warn!("Already tracking SIGUSR1");
84 return;
85 }
86
87 let result = sigs::flag::register(sigs::consts::SIGUSR1, self.usr1_is_set.clone());
88
89 if let Err(e) = result {
90 panic!("Cannot register graceful usr1 handler: {}", e);
91 }
92
93 self.usr1_tracked = true;
94 }
95
96 pub fn usr1_is_set(&self) -> bool {
97 self.usr1_is_set.load(Ordering::Relaxed)
98 }
99
100 pub fn clear_usr1(&mut self) {
101 self.usr1_is_set.store(false, Ordering::Relaxed);
102 }
103
104 pub fn track_usr2(&mut self) {
105 if self.usr2_tracked {
106 log::warn!("Already tracking SIGUSR2");
107 return;
108 }
109
110 let result = sigs::flag::register(sigs::consts::SIGUSR2, self.usr2_is_set.clone());
111
112 if let Err(e) = result {
113 panic!("Cannot register graceful usr2 handler: {}", e);
114 }
115
116 self.usr2_tracked = true;
117 }
118
119 pub fn usr2_is_set(&self) -> bool {
120 self.usr2_is_set.load(Ordering::Relaxed)
121 }
122
123 pub fn clear_usr2(&mut self) {
124 self.usr2_is_set.store(false, Ordering::Relaxed);
125 }
126
127 pub fn track_graceful_shutdown(&mut self) {
143 if self.graceful_shutdown_tracked {
144 log::warn!("Already tracking graceful shutdowns");
145 return;
146 }
147
148 let result = sigs::flag::register(SIG_GRACEFUL_SHUTDOWN, self.graceful_shutdown.clone());
149
150 if let Err(e) = result {
151 panic!("Cannot register graceful shutdown handler: {}", e);
152 }
153
154 self.graceful_shutdown_tracked = true;
155 }
156
157 pub fn graceful_shutdown_requested(&self) -> bool {
158 self.graceful_shutdown.load(Ordering::Relaxed)
159 }
160
161 pub fn track_fast_shutdown(&mut self) {
176 if self.fast_shutdown_tracked {
177 log::warn!("Already tracking fast shutdowns");
178 return;
179 }
180
181 let result = sigs::flag::register(SIG_FAST_SHUTDOWN, self.fast_shutdown.clone());
182
183 if let Err(e) = result {
184 panic!("Cannot register fast shutdown handler: {}", e);
185 }
186
187 self.fast_shutdown_tracked = true;
188 }
189
190 pub fn fast_shutdown_requested(&self) -> bool {
191 self.fast_shutdown.load(Ordering::Relaxed)
192 }
193
194 pub fn track_reload(&mut self) {
214 if self.reload_tracked {
215 log::warn!("Already tracking reload signals");
216 return;
217 }
218
219 let result = sigs::flag::register(SIG_RELOAD, self.reload.clone());
220
221 if let Err(e) = result {
222 panic!("Cannot register fast shutdown handler: {}", e);
223 }
224
225 self.reload_tracked = true;
226 }
227
228 pub fn reload_requested(&self) -> bool {
229 self.reload.load(Ordering::Relaxed)
230 }
231
232 pub fn handle_reload_requested(&mut self) {
235 self.reload.store(false, Ordering::Relaxed);
236
237 let epoch: u64 = SystemTime::now()
238 .duration_since(SystemTime::UNIX_EPOCH)
239 .expect("Epoch Duration Is Sane")
240 .as_millis()
241 .try_into()
243 .expect("Epoch Milliseconds is way too big?");
244
245 self.reload_request_time.store(epoch, Ordering::Relaxed);
246 }
247
248 pub fn reload_request_time(&self) -> u64 {
254 self.reload_request_time.load(Ordering::Relaxed)
255 }
256}