1use libc::{
6 c_int, pthread_kill, pthread_sigmask, pthread_t, sigaction, sigaddset, sigemptyset, siginfo_t,
7 sigismember, sigpending, sigset_t, sigtimedwait, timespec, EAGAIN, EINTR, EINVAL, SA_RESTART,
8 SIG_BLOCK, SIG_UNBLOCK,
9};
10
11use std::mem;
12use std::os::unix::thread::JoinHandleExt;
13use std::ptr::{null, null_mut};
14use std::result;
15use std::thread::JoinHandle;
16
17use {errno, errno_result};
18
19#[derive(Debug)]
20pub enum Error {
21 CreateSigset(errno::Error),
23 SignalAlreadyBlocked(c_int),
25 CompareBlockedSignals(errno::Error),
27 BlockSignal(errno::Error),
29 RetrieveSignalMask(i32),
31 UnblockSignal(errno::Error),
33 ClearWaitPending(errno::Error),
35 ClearGetPending(errno::Error),
37 ClearCheckPending(errno::Error),
39}
40
41pub type SignalResult<T> = result::Result<T, Error>;
42
43#[link(name = "c")]
44extern "C" {
45 fn __libc_current_sigrtmin() -> c_int;
46 fn __libc_current_sigrtmax() -> c_int;
47}
48
49#[allow(non_snake_case)]
51pub fn SIGRTMIN() -> c_int {
52 unsafe { __libc_current_sigrtmin() }
53}
54
55#[allow(non_snake_case)]
57pub fn SIGRTMAX() -> c_int {
58 unsafe { __libc_current_sigrtmax() }
59}
60
61fn valid_signal_num(num: c_int) -> bool {
62 num >= SIGRTMIN() && num <= SIGRTMAX()
63}
64
65pub unsafe fn register_signal_handler(
72 num: c_int,
73 handler: extern "C" fn() -> (),
74) -> errno::Result<()> {
75 if !valid_signal_num(num) {
76 return Err(errno::Error::new(EINVAL));
77 }
78
79 let mut sigact: sigaction = mem::zeroed();
80 sigact.sa_flags = SA_RESTART;
81 sigact.sa_sigaction = handler as *const () as usize;
82
83 let ret = sigaction(num, &sigact, null_mut());
84 if ret < 0 {
85 return errno_result();
86 }
87
88 Ok(())
89}
90
91pub fn create_sigset(signals: &[c_int]) -> errno::Result<sigset_t> {
95 let mut sigset: sigset_t = unsafe { mem::zeroed() };
97
98 let ret = unsafe { sigemptyset(&mut sigset) };
100 if ret < 0 {
101 return errno_result();
102 }
103
104 for signal in signals {
105 let ret = unsafe { sigaddset(&mut sigset, *signal) };
107 if ret < 0 {
108 return errno_result();
109 }
110 }
111
112 Ok(sigset)
113}
114
115pub fn get_blocked_signals() -> SignalResult<Vec<c_int>> {
117 let mut mask = Vec::new();
118
119 unsafe {
121 let mut old_sigset: sigset_t = mem::zeroed();
122 let ret = pthread_sigmask(SIG_BLOCK, null(), &mut old_sigset as *mut sigset_t);
123 if ret < 0 {
124 return Err(Error::RetrieveSignalMask(ret));
125 }
126
127 for num in 0..=SIGRTMAX() {
128 if sigismember(&old_sigset, num) > 0 {
129 mask.push(num);
130 }
131 }
132 }
133
134 Ok(mask)
135}
136
137pub fn block_signal(num: c_int) -> SignalResult<()> {
142 let sigset = create_sigset(&[num]).map_err(Error::CreateSigset)?;
143
144 unsafe {
146 let mut old_sigset: sigset_t = mem::zeroed();
147 let ret = pthread_sigmask(SIG_BLOCK, &sigset, &mut old_sigset as *mut sigset_t);
148 if ret < 0 {
149 return Err(Error::BlockSignal(errno::Error::last()));
150 }
151 let ret = sigismember(&old_sigset, num);
152 if ret < 0 {
153 return Err(Error::CompareBlockedSignals(errno::Error::last()));
154 } else if ret > 0 {
155 return Err(Error::SignalAlreadyBlocked(num));
156 }
157 }
158 Ok(())
159}
160
161pub fn unblock_signal(num: c_int) -> SignalResult<()> {
163 let sigset = create_sigset(&[num]).map_err(Error::CreateSigset)?;
164
165 let ret = unsafe { pthread_sigmask(SIG_UNBLOCK, &sigset, null_mut()) };
167 if ret < 0 {
168 return Err(Error::UnblockSignal(errno::Error::last()));
169 }
170 Ok(())
171}
172
173pub fn clear_signal(num: c_int) -> SignalResult<()> {
175 let sigset = create_sigset(&[num]).map_err(Error::CreateSigset)?;
176
177 while {
178 unsafe {
181 let mut siginfo: siginfo_t = mem::zeroed();
182 let ts = timespec {
183 tv_sec: 0,
184 tv_nsec: 0,
185 };
186 let ret = sigtimedwait(&sigset, &mut siginfo, &ts);
189 if ret < 0 {
190 let e = errno::Error::last();
191 match e.errno() {
192 EAGAIN | EINTR => {}
193 _ => {
194 return Err(Error::ClearWaitPending(errno::Error::last()));
195 }
196 }
197 }
198
199 let mut chkset: sigset_t = mem::zeroed();
201 let ret = sigpending(&mut chkset);
203 if ret < 0 {
204 return Err(Error::ClearGetPending(errno::Error::last()));
205 }
206
207 let ret = sigismember(&chkset, num);
208 if ret < 0 {
209 return Err(Error::ClearCheckPending(errno::Error::last()));
210 }
211
212 ret != 0
214 }
215 } {}
216
217 Ok(())
218}
219
220pub unsafe trait Killable {
228 fn pthread_handle(&self) -> pthread_t;
229
230 fn kill(&self, num: c_int) -> errno::Result<()> {
234 if !valid_signal_num(num) {
235 return Err(errno::Error::new(EINVAL));
236 }
237
238 let ret = unsafe { pthread_kill(self.pthread_handle(), num) };
241 if ret < 0 {
242 return errno_result();
243 }
244 Ok(())
245 }
246}
247
248unsafe impl<T> Killable for JoinHandle<T> {
250 fn pthread_handle(&self) -> pthread_t {
251 self.as_pthread_t()
252 }
253}