1use crate::CoreError;
12use crate::error::syscall_ret;
13use crate::fd::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
39pub fn kill(pid: i32, sig: i32) -> Result<(), CoreError> {
43 syscall_ret(unsafe { libc::kill(pid, sig) }, "kill")
44}
45
46static SHUTDOWN_FLAG_PTR: AtomicPtr<AtomicBool> = AtomicPtr::new(std::ptr::null_mut());
47
48extern "C" fn shutdown_signal_handler(_sig: libc::c_int) {
49 let flag = SHUTDOWN_FLAG_PTR.load(Ordering::Relaxed);
50 if !flag.is_null() {
51 unsafe {
52 (*flag).store(true, Ordering::Release);
53 }
54 }
55}
56
57pub fn install_shutdown_flag(flag: &'static AtomicBool) -> Result<(), CoreError> {
79 install_shutdown_flag_inner(flag).map(|_| ())
80}
81
82pub struct ShutdownFlagGuard {
89 old_sigint: libc::sigaction,
90 old_sigterm: libc::sigaction,
91 old_flag: *mut AtomicBool,
92}
93
94impl Drop for ShutdownFlagGuard {
95 fn drop(&mut self) {
96 SHUTDOWN_FLAG_PTR.store(self.old_flag, Ordering::Release);
97 let _ = restore_signal_handler(SIGTERM, &self.old_sigterm);
98 let _ = restore_signal_handler(SIGINT, &self.old_sigint);
99 }
100}
101
102pub fn install_shutdown_flag_guard(
108 flag: &'static AtomicBool,
109) -> Result<ShutdownFlagGuard, CoreError> {
110 let (old_sigint, old_sigterm, old_flag) = install_shutdown_flag_inner(flag)?;
111 Ok(ShutdownFlagGuard {
112 old_sigint,
113 old_sigterm,
114 old_flag,
115 })
116}
117
118fn install_shutdown_flag_inner(
119 flag: &'static AtomicBool,
120) -> Result<(libc::sigaction, libc::sigaction, *mut AtomicBool), CoreError> {
121 let old_flag = SHUTDOWN_FLAG_PTR.load(Ordering::Acquire);
122 let old_sigint = install_signal_handler(SIGINT)?;
123 match install_signal_handler(SIGTERM) {
124 Ok(old_sigterm) => {
125 SHUTDOWN_FLAG_PTR.store(
126 flag as *const AtomicBool as *mut AtomicBool,
127 Ordering::Release,
128 );
129 Ok((old_sigint, old_sigterm, old_flag))
130 }
131 Err(err) => {
132 restore_signal_handler(SIGINT, &old_sigint)?;
133 Err(err)
134 }
135 }
136}
137
138#[inline]
140pub fn shutdown_requested(flag: &AtomicBool) -> bool {
141 flag.load(Ordering::Acquire)
142}
143
144fn install_signal_handler(sig: libc::c_int) -> Result<libc::sigaction, CoreError> {
145 let mut action: libc::sigaction = unsafe { std::mem::zeroed() };
146 let mut old_action: libc::sigaction = unsafe { std::mem::zeroed() };
147 action.sa_sigaction = shutdown_signal_handler as *const () as usize;
148 action.sa_flags = 0;
149 unsafe { libc::sigemptyset(&mut action.sa_mask) };
150
151 let ret = unsafe { libc::sigaction(sig, &action, &mut old_action) };
152 if ret == -1 {
153 Err(last_sigaction_error(sig))
154 } else {
155 Ok(old_action)
156 }
157}
158
159fn restore_signal_handler(sig: libc::c_int, old_action: &libc::sigaction) -> Result<(), CoreError> {
160 let ret = unsafe { libc::sigaction(sig, old_action, std::ptr::null_mut()) };
161 if ret == -1 {
162 Err(last_sigaction_error(sig))
163 } else {
164 Ok(())
165 }
166}
167
168fn last_sigaction_error(sig: libc::c_int) -> CoreError {
169 let op = match sig {
170 SIGINT => "sigaction(SIGINT)",
171 SIGTERM => "sigaction(SIGTERM)",
172 _ => "sigaction",
173 };
174 let code = std::io::Error::last_os_error().raw_os_error().unwrap_or(0);
175 CoreError::sys(code, op)
176}
177
178pub struct SignalRuntime;
180
181impl SignalRuntime {
182 pub fn empty_set() -> SignalSet {
184 let mut set: SignalSet = unsafe { std::mem::zeroed() };
185 unsafe { libc::sigemptyset(&mut set) };
186 set
187 }
188
189 pub fn set_with(signals: &[i32]) -> Result<SignalSet, CoreError> {
194 let mut set: SignalSet = unsafe { std::mem::zeroed() };
195 unsafe { libc::sigemptyset(&mut set) };
196 for &sig in signals {
197 let ret = unsafe { libc::sigaddset(&mut set, sig) };
198 if ret == -1 {
199 return Err(CoreError::sys(libc::EINVAL, "sigaddset"));
200 }
201 }
202 Ok(set)
203 }
204
205 pub fn block_current_thread(signals: &SignalSet) -> Result<SignalSet, CoreError> {
210 let mut previous = Self::empty_set();
211 let result = unsafe { libc::pthread_sigmask(libc::SIG_BLOCK, signals, &mut previous) };
212 if result == 0 {
213 Ok(previous)
214 } else {
215 Err(CoreError::sys(result, "pthread_sigmask(SIG_BLOCK)"))
216 }
217 }
218
219 pub fn restore_current_thread(mask: &SignalSet) -> Result<(), CoreError> {
224 let result =
225 unsafe { libc::pthread_sigmask(libc::SIG_SETMASK, mask, std::ptr::null_mut()) };
226 if result == 0 {
227 Ok(())
228 } else {
229 Err(CoreError::sys(result, "pthread_sigmask(SIG_SETMASK)"))
230 }
231 }
232
233 pub fn wait(signals: &SignalSet) -> Result<i32, CoreError> {
238 let mut received_signal = 0;
239 let result = unsafe { libc::sigwait(signals, &mut received_signal) };
240 if result == 0 {
241 Ok(received_signal)
242 } else {
243 Err(CoreError::sys(result, "sigwait"))
244 }
245 }
246
247 pub fn interrupt_thread(thread: ThreadId, signal: i32) -> Result<(), CoreError> {
253 let result = unsafe { libc::pthread_kill(thread, signal) };
254 if result == 0 {
255 Ok(())
256 } else {
257 Err(CoreError::sys(result, "pthread_kill"))
258 }
259 }
260
261 pub fn set_current_thread_mask(how: i32, signals: &SignalSet) -> Result<SignalSet, CoreError> {
263 let mut previous = Self::empty_set();
264 let result = unsafe { libc::pthread_sigmask(how, signals, &mut previous) };
265 if result == 0 {
266 Ok(previous)
267 } else {
268 let op = match how {
269 libc::SIG_BLOCK => "pthread_sigmask(SIG_BLOCK)",
270 libc::SIG_UNBLOCK => "pthread_sigmask(SIG_UNBLOCK)",
271 libc::SIG_SETMASK => "pthread_sigmask(SIG_SETMASK)",
272 _ => "pthread_sigmask",
273 };
274 Err(CoreError::sys(result, op))
275 }
276 }
277
278 pub fn unblock_all() -> Result<(), CoreError> {
280 let empty_mask = Self::empty_set();
281 let r =
282 unsafe { libc::pthread_sigmask(libc::SIG_SETMASK, &empty_mask, std::ptr::null_mut()) };
283 if r != 0 {
284 Err(CoreError::sys(r, "pthread_sigmask(SIG_SETMASK)"))
285 } else {
286 Ok(())
287 }
288 }
289
290 pub fn signalfd_new(signals: &SignalSet) -> Result<Fd, CoreError> {
312 let fd = unsafe { libc::signalfd(-1, signals, libc::SFD_NONBLOCK | libc::SFD_CLOEXEC) };
313 syscall_ret(fd, "signalfd")?;
314 Fd::new(fd, "signalfd")
315 }
316
317 pub fn register_handler(
334 sig: i32,
335 handler: extern "C" fn(i32),
336 ) -> Result<libc::sigaction, CoreError> {
337 let mut action: libc::sigaction = unsafe { std::mem::zeroed() };
338 let mut old_action: libc::sigaction = unsafe { std::mem::zeroed() };
339 action.sa_sigaction = handler as *const () as usize;
340 action.sa_flags = 0;
341 unsafe { libc::sigemptyset(&mut action.sa_mask) };
342
343 let ret = unsafe { libc::sigaction(sig, &action, &mut old_action) };
344 if ret == -1 {
345 let code = std::io::Error::last_os_error().raw_os_error().unwrap_or(0);
346 Err(CoreError::sys(code, "sigaction"))
347 } else {
348 Ok(old_action)
349 }
350 }
351
352 pub fn reset_default(sig: i32) -> Result<(), CoreError> {
357 let prev = unsafe { libc::signal(sig, libc::SIG_DFL) };
358 if prev == libc::SIG_ERR {
359 Err(CoreError::sys(
360 std::io::Error::last_os_error().raw_os_error().unwrap_or(0),
361 "signal(SIG_DFL)",
362 ))
363 } else {
364 Ok(())
365 }
366 }
367}