1use crate::CoreError;
12use crate::error::syscall_ret;
13use std::sync::atomic::{AtomicBool, AtomicPtr, Ordering};
14
15pub type SignalSet = libc::sigset_t;
16pub type ThreadId = libc::pthread_t;
17
18pub const SIGINT: i32 = libc::SIGINT;
19pub const SIGTERM: i32 = libc::SIGTERM;
20pub const SIGPIPE: i32 = libc::SIGPIPE;
21pub const SIGKILL: i32 = libc::SIGKILL;
22
23static SHUTDOWN_FLAG_PTR: AtomicPtr<AtomicBool> = AtomicPtr::new(std::ptr::null_mut());
24
25extern "C" fn shutdown_signal_handler(_sig: libc::c_int) {
26 let flag = SHUTDOWN_FLAG_PTR.load(Ordering::Relaxed);
27 if !flag.is_null() {
28 unsafe {
29 (*flag).store(true, Ordering::Release);
30 }
31 }
32}
33
34pub fn install_shutdown_flag(flag: &'static AtomicBool) -> Result<(), CoreError> {
42 install_shutdown_flag_inner(flag).map(|_| ())
43}
44
45pub struct ShutdownFlagGuard {
47 old_sigint: libc::sigaction,
48 old_sigterm: libc::sigaction,
49 old_flag: *mut AtomicBool,
50}
51
52impl Drop for ShutdownFlagGuard {
53 fn drop(&mut self) {
54 SHUTDOWN_FLAG_PTR.store(self.old_flag, Ordering::Release);
55 let _ = restore_signal_handler(SIGTERM, &self.old_sigterm);
56 let _ = restore_signal_handler(SIGINT, &self.old_sigint);
57 }
58}
59
60pub fn install_shutdown_flag_guard(
66 flag: &'static AtomicBool,
67) -> Result<ShutdownFlagGuard, CoreError> {
68 let (old_sigint, old_sigterm, old_flag) = install_shutdown_flag_inner(flag)?;
69 Ok(ShutdownFlagGuard {
70 old_sigint,
71 old_sigterm,
72 old_flag,
73 })
74}
75
76fn install_shutdown_flag_inner(
77 flag: &'static AtomicBool,
78) -> Result<(libc::sigaction, libc::sigaction, *mut AtomicBool), CoreError> {
79 let old_flag = SHUTDOWN_FLAG_PTR.load(Ordering::Acquire);
80 let old_sigint = install_signal_handler(SIGINT)?;
81 match install_signal_handler(SIGTERM) {
82 Ok(old_sigterm) => {
83 SHUTDOWN_FLAG_PTR.store(
84 flag as *const AtomicBool as *mut AtomicBool,
85 Ordering::Release,
86 );
87 Ok((old_sigint, old_sigterm, old_flag))
88 }
89 Err(err) => {
90 restore_signal_handler(SIGINT, &old_sigint)?;
91 Err(err)
92 }
93 }
94}
95
96#[inline]
98pub fn shutdown_requested(flag: &AtomicBool) -> bool {
99 flag.load(Ordering::Acquire)
100}
101
102fn install_signal_handler(sig: libc::c_int) -> Result<libc::sigaction, CoreError> {
103 let mut action: libc::sigaction = unsafe { std::mem::zeroed() };
104 let mut old_action: libc::sigaction = unsafe { std::mem::zeroed() };
105 action.sa_sigaction = shutdown_signal_handler as *const () as usize;
106 action.sa_flags = 0;
107 unsafe { libc::sigemptyset(&mut action.sa_mask) };
108
109 let ret = unsafe { libc::sigaction(sig, &action, &mut old_action) };
110 if ret == -1 {
111 Err(last_sigaction_error(sig))
112 } else {
113 Ok(old_action)
114 }
115}
116
117fn restore_signal_handler(sig: libc::c_int, old_action: &libc::sigaction) -> Result<(), CoreError> {
118 let ret = unsafe { libc::sigaction(sig, old_action, std::ptr::null_mut()) };
119 if ret == -1 {
120 Err(last_sigaction_error(sig))
121 } else {
122 Ok(())
123 }
124}
125
126fn last_sigaction_error(sig: libc::c_int) -> CoreError {
127 let op = match sig {
128 SIGINT => "sigaction(SIGINT)",
129 SIGTERM => "sigaction(SIGTERM)",
130 _ => "sigaction",
131 };
132 let code = std::io::Error::last_os_error().raw_os_error().unwrap_or(0);
133 CoreError::sys(code, op)
134}
135
136pub struct SignalRuntime;
138
139impl SignalRuntime {
140 pub fn empty_set() -> SignalSet {
142 let mut set: SignalSet = unsafe { std::mem::zeroed() };
143 unsafe { libc::sigemptyset(&mut set) };
144 set
145 }
146
147 pub fn set_with(signals: &[i32]) -> Result<SignalSet, CoreError> {
149 let mut set: SignalSet = unsafe { std::mem::zeroed() };
150 unsafe { libc::sigemptyset(&mut set) };
151 for &sig in signals {
152 let ret = unsafe { libc::sigaddset(&mut set, sig) };
153 if ret == -1 {
154 return Err(CoreError::sys(libc::EINVAL, "sigaddset"));
155 }
156 }
157 Ok(set)
158 }
159
160 pub fn block_current_thread(signals: &SignalSet) -> Result<SignalSet, CoreError> {
162 let mut previous = Self::empty_set();
163 let result = unsafe { libc::pthread_sigmask(libc::SIG_BLOCK, signals, &mut previous) };
164 if result == 0 {
165 Ok(previous)
166 } else {
167 Err(CoreError::sys(result, "pthread_sigmask(SIG_BLOCK)"))
168 }
169 }
170
171 pub fn restore_current_thread(mask: &SignalSet) -> Result<(), CoreError> {
173 let result =
174 unsafe { libc::pthread_sigmask(libc::SIG_SETMASK, mask, std::ptr::null_mut()) };
175 if result == 0 {
176 Ok(())
177 } else {
178 Err(CoreError::sys(result, "pthread_sigmask(SIG_SETMASK)"))
179 }
180 }
181
182 pub fn wait(signals: &SignalSet) -> Result<i32, CoreError> {
184 let mut received_signal = 0;
185 let result = unsafe { libc::sigwait(signals, &mut received_signal) };
186 if result == 0 {
187 Ok(received_signal)
188 } else {
189 Err(CoreError::sys(result, "sigwait"))
190 }
191 }
192
193 pub fn interrupt_thread(thread: ThreadId, signal: i32) -> Result<(), CoreError> {
195 let result = unsafe { libc::pthread_kill(thread, signal) };
196 if result == 0 {
197 Ok(())
198 } else {
199 Err(CoreError::sys(result, "pthread_kill"))
200 }
201 }
202
203 pub fn unblock_all() -> Result<(), CoreError> {
205 let empty_mask = Self::empty_set();
206 let r = unsafe { libc::sigprocmask(libc::SIG_SETMASK, &empty_mask, std::ptr::null_mut()) };
207 syscall_ret(r, "sigprocmask")
208 }
209
210 pub fn reset_default(sig: i32) -> Result<(), CoreError> {
212 let prev = unsafe { libc::signal(sig, libc::SIG_DFL) };
213 if prev == libc::SIG_ERR {
214 Err(CoreError::sys(
215 std::io::Error::last_os_error().raw_os_error().unwrap_or(0),
216 "signal(SIG_DFL)",
217 ))
218 } else {
219 Ok(())
220 }
221 }
222}