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(
256 how: i32,
257 signals: &SignalSet,
258 ) -> Result<SignalSet, CoreError> {
259 let mut previous = Self::empty_set();
260 let result = unsafe { libc::pthread_sigmask(how, signals, &mut previous) };
261 if result == 0 {
262 Ok(previous)
263 } else {
264 let op = match how {
265 libc::SIG_BLOCK => "pthread_sigmask(SIG_BLOCK)",
266 libc::SIG_UNBLOCK => "pthread_sigmask(SIG_UNBLOCK)",
267 libc::SIG_SETMASK => "pthread_sigmask(SIG_SETMASK)",
268 _ => "pthread_sigmask",
269 };
270 Err(CoreError::sys(result, op))
271 }
272 }
273
274 pub fn unblock_all() -> Result<(), CoreError> {
276 let empty_mask = Self::empty_set();
277 let r = unsafe { libc::pthread_sigmask(libc::SIG_SETMASK, &empty_mask, std::ptr::null_mut()) };
278 if r != 0 {
279 Err(CoreError::sys(r, "pthread_sigmask(SIG_SETMASK)"))
280 } else {
281 Ok(())
282 }
283 }
284
285 pub fn signalfd_new(signals: &SignalSet) -> Result<Fd, CoreError> {
307 let fd = unsafe { libc::signalfd(-1, signals, libc::SFD_NONBLOCK | libc::SFD_CLOEXEC) };
308 syscall_ret(fd, "signalfd")?;
309 Fd::new(fd, "signalfd")
310 }
311
312 pub fn register_handler(
329 sig: i32,
330 handler: extern "C" fn(i32),
331 ) -> Result<libc::sigaction, CoreError> {
332 let mut action: libc::sigaction = unsafe { std::mem::zeroed() };
333 let mut old_action: libc::sigaction = unsafe { std::mem::zeroed() };
334 action.sa_sigaction = handler as *const () as usize;
335 action.sa_flags = 0;
336 unsafe { libc::sigemptyset(&mut action.sa_mask) };
337
338 let ret = unsafe { libc::sigaction(sig, &action, &mut old_action) };
339 if ret == -1 {
340 let code = std::io::Error::last_os_error().raw_os_error().unwrap_or(0);
341 Err(CoreError::sys(code, "sigaction"))
342 } else {
343 Ok(old_action)
344 }
345 }
346
347 pub fn reset_default(sig: i32) -> Result<(), CoreError> {
352 let prev = unsafe { libc::signal(sig, libc::SIG_DFL) };
353 if prev == libc::SIG_ERR {
354 Err(CoreError::sys(
355 std::io::Error::last_os_error().raw_os_error().unwrap_or(0),
356 "signal(SIG_DFL)",
357 ))
358 } else {
359 Ok(())
360 }
361 }
362}