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;
25pub const SIGCHLD: i32 = libc::SIGCHLD;
26pub const SIGHUP: i32 = libc::SIGHUP;
27
28pub type SignalfdSiginfo = libc::signalfd_siginfo;
30
31pub unsafe fn signal_ignore(sig: i32) {
36 unsafe { libc::signal(sig, libc::SIG_IGN) };
37}
38
39static SHUTDOWN_FLAG_PTR: AtomicPtr<AtomicBool> = AtomicPtr::new(std::ptr::null_mut());
40
41extern "C" fn shutdown_signal_handler(_sig: libc::c_int) {
42 let flag = SHUTDOWN_FLAG_PTR.load(Ordering::Relaxed);
43 if !flag.is_null() {
44 unsafe {
45 (*flag).store(true, Ordering::Release);
46 }
47 }
48}
49
50pub fn install_shutdown_flag(flag: &'static AtomicBool) -> Result<(), CoreError> {
72 install_shutdown_flag_inner(flag).map(|_| ())
73}
74
75pub struct ShutdownFlagGuard {
82 old_sigint: libc::sigaction,
83 old_sigterm: libc::sigaction,
84 old_flag: *mut AtomicBool,
85}
86
87impl Drop for ShutdownFlagGuard {
88 fn drop(&mut self) {
89 SHUTDOWN_FLAG_PTR.store(self.old_flag, Ordering::Release);
90 let _ = restore_signal_handler(SIGTERM, &self.old_sigterm);
91 let _ = restore_signal_handler(SIGINT, &self.old_sigint);
92 }
93}
94
95pub fn install_shutdown_flag_guard(
101 flag: &'static AtomicBool,
102) -> Result<ShutdownFlagGuard, CoreError> {
103 let (old_sigint, old_sigterm, old_flag) = install_shutdown_flag_inner(flag)?;
104 Ok(ShutdownFlagGuard {
105 old_sigint,
106 old_sigterm,
107 old_flag,
108 })
109}
110
111fn install_shutdown_flag_inner(
112 flag: &'static AtomicBool,
113) -> Result<(libc::sigaction, libc::sigaction, *mut AtomicBool), CoreError> {
114 let old_flag = SHUTDOWN_FLAG_PTR.load(Ordering::Acquire);
115 let old_sigint = install_signal_handler(SIGINT)?;
116 match install_signal_handler(SIGTERM) {
117 Ok(old_sigterm) => {
118 SHUTDOWN_FLAG_PTR.store(
119 flag as *const AtomicBool as *mut AtomicBool,
120 Ordering::Release,
121 );
122 Ok((old_sigint, old_sigterm, old_flag))
123 }
124 Err(err) => {
125 restore_signal_handler(SIGINT, &old_sigint)?;
126 Err(err)
127 }
128 }
129}
130
131#[inline]
133pub fn shutdown_requested(flag: &AtomicBool) -> bool {
134 flag.load(Ordering::Acquire)
135}
136
137fn install_signal_handler(sig: libc::c_int) -> Result<libc::sigaction, CoreError> {
138 let mut action: libc::sigaction = unsafe { std::mem::zeroed() };
139 let mut old_action: libc::sigaction = unsafe { std::mem::zeroed() };
140 action.sa_sigaction = shutdown_signal_handler as *const () as usize;
141 action.sa_flags = 0;
142 unsafe { libc::sigemptyset(&mut action.sa_mask) };
143
144 let ret = unsafe { libc::sigaction(sig, &action, &mut old_action) };
145 if ret == -1 {
146 Err(last_sigaction_error(sig))
147 } else {
148 Ok(old_action)
149 }
150}
151
152fn restore_signal_handler(sig: libc::c_int, old_action: &libc::sigaction) -> Result<(), CoreError> {
153 let ret = unsafe { libc::sigaction(sig, old_action, std::ptr::null_mut()) };
154 if ret == -1 {
155 Err(last_sigaction_error(sig))
156 } else {
157 Ok(())
158 }
159}
160
161fn last_sigaction_error(sig: libc::c_int) -> CoreError {
162 let op = match sig {
163 SIGINT => "sigaction(SIGINT)",
164 SIGTERM => "sigaction(SIGTERM)",
165 _ => "sigaction",
166 };
167 let code = std::io::Error::last_os_error().raw_os_error().unwrap_or(0);
168 CoreError::sys(code, op)
169}
170
171pub struct SignalRuntime;
173
174impl SignalRuntime {
175 pub fn empty_set() -> SignalSet {
177 let mut set: SignalSet = unsafe { std::mem::zeroed() };
178 unsafe { libc::sigemptyset(&mut set) };
179 set
180 }
181
182 pub fn set_with(signals: &[i32]) -> Result<SignalSet, CoreError> {
187 let mut set: SignalSet = unsafe { std::mem::zeroed() };
188 unsafe { libc::sigemptyset(&mut set) };
189 for &sig in signals {
190 let ret = unsafe { libc::sigaddset(&mut set, sig) };
191 if ret == -1 {
192 return Err(CoreError::sys(libc::EINVAL, "sigaddset"));
193 }
194 }
195 Ok(set)
196 }
197
198 pub fn block_current_thread(signals: &SignalSet) -> Result<SignalSet, CoreError> {
203 let mut previous = Self::empty_set();
204 let result = unsafe { libc::pthread_sigmask(libc::SIG_BLOCK, signals, &mut previous) };
205 if result == 0 {
206 Ok(previous)
207 } else {
208 Err(CoreError::sys(result, "pthread_sigmask(SIG_BLOCK)"))
209 }
210 }
211
212 pub fn restore_current_thread(mask: &SignalSet) -> Result<(), CoreError> {
217 let result =
218 unsafe { libc::pthread_sigmask(libc::SIG_SETMASK, mask, std::ptr::null_mut()) };
219 if result == 0 {
220 Ok(())
221 } else {
222 Err(CoreError::sys(result, "pthread_sigmask(SIG_SETMASK)"))
223 }
224 }
225
226 pub fn wait(signals: &SignalSet) -> Result<i32, CoreError> {
231 let mut received_signal = 0;
232 let result = unsafe { libc::sigwait(signals, &mut received_signal) };
233 if result == 0 {
234 Ok(received_signal)
235 } else {
236 Err(CoreError::sys(result, "sigwait"))
237 }
238 }
239
240 pub fn interrupt_thread(thread: ThreadId, signal: i32) -> Result<(), CoreError> {
246 let result = unsafe { libc::pthread_kill(thread, signal) };
247 if result == 0 {
248 Ok(())
249 } else {
250 Err(CoreError::sys(result, "pthread_kill"))
251 }
252 }
253
254 pub fn set_current_thread_mask(how: i32, signals: &SignalSet) -> Result<SignalSet, CoreError> {
256 let mut previous = Self::empty_set();
257 let result = unsafe { libc::pthread_sigmask(how, signals, &mut previous) };
258 if result == 0 {
259 Ok(previous)
260 } else {
261 let op = match how {
262 libc::SIG_BLOCK => "pthread_sigmask(SIG_BLOCK)",
263 libc::SIG_UNBLOCK => "pthread_sigmask(SIG_UNBLOCK)",
264 libc::SIG_SETMASK => "pthread_sigmask(SIG_SETMASK)",
265 _ => "pthread_sigmask",
266 };
267 Err(CoreError::sys(result, op))
268 }
269 }
270
271 pub fn unblock_all() -> Result<(), CoreError> {
273 let empty_mask = Self::empty_set();
274 let r =
275 unsafe { libc::pthread_sigmask(libc::SIG_SETMASK, &empty_mask, std::ptr::null_mut()) };
276 if r != 0 {
277 Err(CoreError::sys(r, "pthread_sigmask(SIG_SETMASK)"))
278 } else {
279 Ok(())
280 }
281 }
282
283 pub fn signalfd_new(signals: &SignalSet) -> Result<Fd, CoreError> {
305 let fd = unsafe { libc::signalfd(-1, signals, libc::SFD_NONBLOCK | libc::SFD_CLOEXEC) };
306 syscall_ret(fd, "signalfd")?;
307 Fd::new(fd, "signalfd")
308 }
309
310 pub fn register_handler(
327 sig: i32,
328 handler: extern "C" fn(i32),
329 ) -> Result<libc::sigaction, CoreError> {
330 let mut action: libc::sigaction = unsafe { std::mem::zeroed() };
331 let mut old_action: libc::sigaction = unsafe { std::mem::zeroed() };
332 action.sa_sigaction = handler as *const () as usize;
333 action.sa_flags = 0;
334 unsafe { libc::sigemptyset(&mut action.sa_mask) };
335
336 let ret = unsafe { libc::sigaction(sig, &action, &mut old_action) };
337 if ret == -1 {
338 let code = std::io::Error::last_os_error().raw_os_error().unwrap_or(0);
339 Err(CoreError::sys(code, "sigaction"))
340 } else {
341 Ok(old_action)
342 }
343 }
344
345 pub fn reset_default(sig: i32) -> Result<(), CoreError> {
350 let prev = unsafe { libc::signal(sig, libc::SIG_DFL) };
351 if prev == libc::SIG_ERR {
352 Err(CoreError::sys(
353 std::io::Error::last_os_error().raw_os_error().unwrap_or(0),
354 "signal(SIG_DFL)",
355 ))
356 } else {
357 Ok(())
358 }
359 }
360}