1use crate::CoreError;
12use crate::error::syscall_ret;
13use crate::reactor::Fd;
14use std::sync::atomic::{AtomicBool, AtomicPtr, Ordering};
15
16pub type SignalSet = libc::sigset_t;
17pub type ThreadId = libc::pthread_t;
18
19pub const SIGINT: i32 = libc::SIGINT;
20pub const SIGTERM: i32 = libc::SIGTERM;
21pub const SIGPIPE: i32 = libc::SIGPIPE;
22pub const SIGKILL: i32 = libc::SIGKILL;
23pub const SIGUSR1: i32 = libc::SIGUSR1;
24pub const SIGUSR2: i32 = libc::SIGUSR2;
25
26static SHUTDOWN_FLAG_PTR: AtomicPtr<AtomicBool> = AtomicPtr::new(std::ptr::null_mut());
27
28extern "C" fn shutdown_signal_handler(_sig: libc::c_int) {
29 let flag = SHUTDOWN_FLAG_PTR.load(Ordering::Relaxed);
30 if !flag.is_null() {
31 unsafe {
32 (*flag).store(true, Ordering::Release);
33 }
34 }
35}
36
37pub fn install_shutdown_flag(flag: &'static AtomicBool) -> Result<(), CoreError> {
59 install_shutdown_flag_inner(flag).map(|_| ())
60}
61
62pub struct ShutdownFlagGuard {
69 old_sigint: libc::sigaction,
70 old_sigterm: libc::sigaction,
71 old_flag: *mut AtomicBool,
72}
73
74impl Drop for ShutdownFlagGuard {
75 fn drop(&mut self) {
76 SHUTDOWN_FLAG_PTR.store(self.old_flag, Ordering::Release);
77 let _ = restore_signal_handler(SIGTERM, &self.old_sigterm);
78 let _ = restore_signal_handler(SIGINT, &self.old_sigint);
79 }
80}
81
82pub fn install_shutdown_flag_guard(
88 flag: &'static AtomicBool,
89) -> Result<ShutdownFlagGuard, CoreError> {
90 let (old_sigint, old_sigterm, old_flag) = install_shutdown_flag_inner(flag)?;
91 Ok(ShutdownFlagGuard {
92 old_sigint,
93 old_sigterm,
94 old_flag,
95 })
96}
97
98fn install_shutdown_flag_inner(
99 flag: &'static AtomicBool,
100) -> Result<(libc::sigaction, libc::sigaction, *mut AtomicBool), CoreError> {
101 let old_flag = SHUTDOWN_FLAG_PTR.load(Ordering::Acquire);
102 let old_sigint = install_signal_handler(SIGINT)?;
103 match install_signal_handler(SIGTERM) {
104 Ok(old_sigterm) => {
105 SHUTDOWN_FLAG_PTR.store(
106 flag as *const AtomicBool as *mut AtomicBool,
107 Ordering::Release,
108 );
109 Ok((old_sigint, old_sigterm, old_flag))
110 }
111 Err(err) => {
112 restore_signal_handler(SIGINT, &old_sigint)?;
113 Err(err)
114 }
115 }
116}
117
118#[inline]
120pub fn shutdown_requested(flag: &AtomicBool) -> bool {
121 flag.load(Ordering::Acquire)
122}
123
124fn install_signal_handler(sig: libc::c_int) -> Result<libc::sigaction, CoreError> {
125 let mut action: libc::sigaction = unsafe { std::mem::zeroed() };
126 let mut old_action: libc::sigaction = unsafe { std::mem::zeroed() };
127 action.sa_sigaction = shutdown_signal_handler as *const () as usize;
128 action.sa_flags = 0;
129 unsafe { libc::sigemptyset(&mut action.sa_mask) };
130
131 let ret = unsafe { libc::sigaction(sig, &action, &mut old_action) };
132 if ret == -1 {
133 Err(last_sigaction_error(sig))
134 } else {
135 Ok(old_action)
136 }
137}
138
139fn restore_signal_handler(sig: libc::c_int, old_action: &libc::sigaction) -> Result<(), CoreError> {
140 let ret = unsafe { libc::sigaction(sig, old_action, std::ptr::null_mut()) };
141 if ret == -1 {
142 Err(last_sigaction_error(sig))
143 } else {
144 Ok(())
145 }
146}
147
148fn last_sigaction_error(sig: libc::c_int) -> CoreError {
149 let op = match sig {
150 SIGINT => "sigaction(SIGINT)",
151 SIGTERM => "sigaction(SIGTERM)",
152 _ => "sigaction",
153 };
154 let code = std::io::Error::last_os_error().raw_os_error().unwrap_or(0);
155 CoreError::sys(code, op)
156}
157
158pub struct SignalRuntime;
160
161impl SignalRuntime {
162 pub fn empty_set() -> SignalSet {
164 let mut set: SignalSet = unsafe { std::mem::zeroed() };
165 unsafe { libc::sigemptyset(&mut set) };
166 set
167 }
168
169 pub fn set_with(signals: &[i32]) -> Result<SignalSet, CoreError> {
174 let mut set: SignalSet = unsafe { std::mem::zeroed() };
175 unsafe { libc::sigemptyset(&mut set) };
176 for &sig in signals {
177 let ret = unsafe { libc::sigaddset(&mut set, sig) };
178 if ret == -1 {
179 return Err(CoreError::sys(libc::EINVAL, "sigaddset"));
180 }
181 }
182 Ok(set)
183 }
184
185 pub fn block_current_thread(signals: &SignalSet) -> Result<SignalSet, CoreError> {
190 let mut previous = Self::empty_set();
191 let result = unsafe { libc::pthread_sigmask(libc::SIG_BLOCK, signals, &mut previous) };
192 if result == 0 {
193 Ok(previous)
194 } else {
195 Err(CoreError::sys(result, "pthread_sigmask(SIG_BLOCK)"))
196 }
197 }
198
199 pub fn restore_current_thread(mask: &SignalSet) -> Result<(), CoreError> {
204 let result =
205 unsafe { libc::pthread_sigmask(libc::SIG_SETMASK, mask, std::ptr::null_mut()) };
206 if result == 0 {
207 Ok(())
208 } else {
209 Err(CoreError::sys(result, "pthread_sigmask(SIG_SETMASK)"))
210 }
211 }
212
213 pub fn wait(signals: &SignalSet) -> Result<i32, CoreError> {
218 let mut received_signal = 0;
219 let result = unsafe { libc::sigwait(signals, &mut received_signal) };
220 if result == 0 {
221 Ok(received_signal)
222 } else {
223 Err(CoreError::sys(result, "sigwait"))
224 }
225 }
226
227 pub fn interrupt_thread(thread: ThreadId, signal: i32) -> Result<(), CoreError> {
233 let result = unsafe { libc::pthread_kill(thread, signal) };
234 if result == 0 {
235 Ok(())
236 } else {
237 Err(CoreError::sys(result, "pthread_kill"))
238 }
239 }
240
241 pub fn set_current_thread_mask(
243 how: i32,
244 signals: &SignalSet,
245 ) -> Result<SignalSet, CoreError> {
246 let mut previous = Self::empty_set();
247 let result = unsafe { libc::pthread_sigmask(how, signals, &mut previous) };
248 if result == 0 {
249 Ok(previous)
250 } else {
251 let op = match how {
252 libc::SIG_BLOCK => "pthread_sigmask(SIG_BLOCK)",
253 libc::SIG_UNBLOCK => "pthread_sigmask(SIG_UNBLOCK)",
254 libc::SIG_SETMASK => "pthread_sigmask(SIG_SETMASK)",
255 _ => "pthread_sigmask",
256 };
257 Err(CoreError::sys(result, op))
258 }
259 }
260
261 pub fn unblock_all() -> Result<(), CoreError> {
263 let empty_mask = Self::empty_set();
264 let r = unsafe { libc::pthread_sigmask(libc::SIG_SETMASK, &empty_mask, std::ptr::null_mut()) };
265 if r != 0 {
266 Err(CoreError::sys(r, "pthread_sigmask(SIG_SETMASK)"))
267 } else {
268 Ok(())
269 }
270 }
271
272 pub fn signalfd_new(signals: &SignalSet) -> Result<Fd, CoreError> {
294 let fd = unsafe { libc::signalfd(-1, signals, libc::SFD_NONBLOCK | libc::SFD_CLOEXEC) };
295 syscall_ret(fd, "signalfd")?;
296 Fd::new(fd, "signalfd")
297 }
298
299 pub fn register_handler(
316 sig: i32,
317 handler: extern "C" fn(i32),
318 ) -> Result<libc::sigaction, CoreError> {
319 let mut action: libc::sigaction = unsafe { std::mem::zeroed() };
320 let mut old_action: libc::sigaction = unsafe { std::mem::zeroed() };
321 action.sa_sigaction = handler as *const () as usize;
322 action.sa_flags = 0;
323 unsafe { libc::sigemptyset(&mut action.sa_mask) };
324
325 let ret = unsafe { libc::sigaction(sig, &action, &mut old_action) };
326 if ret == -1 {
327 let code = std::io::Error::last_os_error().raw_os_error().unwrap_or(0);
328 Err(CoreError::sys(code, "sigaction"))
329 } else {
330 Ok(old_action)
331 }
332 }
333
334 pub fn reset_default(sig: i32) -> Result<(), CoreError> {
339 let prev = unsafe { libc::signal(sig, libc::SIG_DFL) };
340 if prev == libc::SIG_ERR {
341 Err(CoreError::sys(
342 std::io::Error::last_os_error().raw_os_error().unwrap_or(0),
343 "signal(SIG_DFL)",
344 ))
345 } else {
346 Ok(())
347 }
348 }
349}