1 // Copyright 2017 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 use 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
11 use std::fmt::{self, Display};
12 use std::io;
13 use std::mem;
14 use std::os::unix::thread::JoinHandleExt;
15 use std::ptr::{null, null_mut};
16 use std::result;
17 use std::thread::JoinHandle;
18
19 use crate::{errno, errno_result};
20
21 #[derive(Debug)]
22 pub enum Error {
23 /// Couldn't create a sigset.
24 CreateSigset(errno::Error),
25 /// The wrapped signal has already been blocked.
26 SignalAlreadyBlocked(c_int),
27 /// Failed to check if the requested signal is in the blocked set already.
28 CompareBlockedSignals(errno::Error),
29 /// The signal could not be blocked.
30 BlockSignal(errno::Error),
31 /// The signal mask could not be retrieved.
32 RetrieveSignalMask(i32),
33 /// The signal could not be unblocked.
34 UnblockSignal(errno::Error),
35 /// Failed to wait for given signal.
36 ClearWaitPending(errno::Error),
37 /// Failed to get pending signals.
38 ClearGetPending(errno::Error),
39 /// Failed to check if given signal is in the set of pending signals.
40 ClearCheckPending(errno::Error),
41 }
42
43 impl Display for Error {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result44 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
45 use self::Error::*;
46
47 match self {
48 CreateSigset(e) => write!(f, "couldn't create a sigset: {}", e),
49 SignalAlreadyBlocked(num) => write!(f, "signal {} already blocked", num),
50 CompareBlockedSignals(e) => write!(
51 f,
52 "failed to check whether requested signal is in the blocked set: {}",
53 e,
54 ),
55 BlockSignal(e) => write!(f, "signal could not be blocked: {}", e),
56 RetrieveSignalMask(errno) => write!(
57 f,
58 "failed to retrieve signal mask: {}",
59 io::Error::from_raw_os_error(*errno),
60 ),
61 UnblockSignal(e) => write!(f, "signal could not be unblocked: {}", e),
62 ClearWaitPending(e) => write!(f, "failed to wait for given signal: {}", e),
63 ClearGetPending(e) => write!(f, "failed to get pending signals: {}", e),
64 ClearCheckPending(e) => write!(
65 f,
66 "failed to check whether given signal is in the pending set: {}",
67 e,
68 ),
69 }
70 }
71 }
72
73 pub type SignalResult<T> = result::Result<T, Error>;
74
75 #[link(name = "c")]
76 extern "C" {
__libc_current_sigrtmin() -> c_int77 fn __libc_current_sigrtmin() -> c_int;
__libc_current_sigrtmax() -> c_int78 fn __libc_current_sigrtmax() -> c_int;
79 }
80
81 /// Returns the minimum (inclusive) real-time signal number.
82 #[allow(non_snake_case)]
SIGRTMIN() -> c_int83 pub fn SIGRTMIN() -> c_int {
84 unsafe { __libc_current_sigrtmin() }
85 }
86
87 /// Returns the maximum (inclusive) real-time signal number.
88 #[allow(non_snake_case)]
SIGRTMAX() -> c_int89 pub fn SIGRTMAX() -> c_int {
90 unsafe { __libc_current_sigrtmax() }
91 }
92
valid_signal_num(num: c_int) -> bool93 fn valid_signal_num(num: c_int) -> bool {
94 num >= SIGRTMIN() && num <= SIGRTMAX()
95 }
96
97 /// Registers `handler` as the signal handler of signum `num`.
98 ///
99 /// The value of `num` must be within [`SIGRTMIN`, `SIGRTMAX`] range.
100 ///
101 /// This is considered unsafe because the given handler will be called asynchronously, interrupting
102 /// whatever the thread was doing and therefore must only do async-signal-safe operations.
register_signal_handler( num: c_int, handler: extern "C" fn() -> (), ) -> errno::Result<()>103 pub unsafe fn register_signal_handler(
104 num: c_int,
105 handler: extern "C" fn() -> (),
106 ) -> errno::Result<()> {
107 if !valid_signal_num(num) {
108 return Err(errno::Error::new(EINVAL));
109 }
110
111 let mut sigact: sigaction = mem::zeroed();
112 sigact.sa_flags = SA_RESTART;
113 sigact.sa_sigaction = handler as *const () as usize;
114
115 let ret = sigaction(num, &sigact, null_mut());
116 if ret < 0 {
117 return errno_result();
118 }
119
120 Ok(())
121 }
122
123 /// Creates `sigset` from an array of signal numbers.
124 ///
125 /// This is a helper function used when we want to manipulate signals.
create_sigset(signals: &[c_int]) -> errno::Result<sigset_t>126 pub fn create_sigset(signals: &[c_int]) -> errno::Result<sigset_t> {
127 // sigset will actually be initialized by sigemptyset below.
128 let mut sigset: sigset_t = unsafe { mem::zeroed() };
129
130 // Safe - return value is checked.
131 let ret = unsafe { sigemptyset(&mut sigset) };
132 if ret < 0 {
133 return errno_result();
134 }
135
136 for signal in signals {
137 // Safe - return value is checked.
138 let ret = unsafe { sigaddset(&mut sigset, *signal) };
139 if ret < 0 {
140 return errno_result();
141 }
142 }
143
144 Ok(sigset)
145 }
146
147 /// Retrieves the signal mask of the current thread as a vector of c_ints.
get_blocked_signals() -> SignalResult<Vec<c_int>>148 pub fn get_blocked_signals() -> SignalResult<Vec<c_int>> {
149 let mut mask = Vec::new();
150
151 // Safe - return values are checked.
152 unsafe {
153 let mut old_sigset: sigset_t = mem::zeroed();
154 let ret = pthread_sigmask(SIG_BLOCK, null(), &mut old_sigset as *mut sigset_t);
155 if ret < 0 {
156 return Err(Error::RetrieveSignalMask(ret));
157 }
158
159 for num in 0..=SIGRTMAX() {
160 if sigismember(&old_sigset, num) > 0 {
161 mask.push(num);
162 }
163 }
164 }
165
166 Ok(mask)
167 }
168
169 /// Masks given signal.
170 ///
171 /// If signal is already blocked the call will fail with Error::SignalAlreadyBlocked
172 /// result.
block_signal(num: c_int) -> SignalResult<()>173 pub fn block_signal(num: c_int) -> SignalResult<()> {
174 let sigset = create_sigset(&[num]).map_err(Error::CreateSigset)?;
175
176 // Safe - return values are checked.
177 unsafe {
178 let mut old_sigset: sigset_t = mem::zeroed();
179 let ret = pthread_sigmask(SIG_BLOCK, &sigset, &mut old_sigset as *mut sigset_t);
180 if ret < 0 {
181 return Err(Error::BlockSignal(errno::Error::last()));
182 }
183 let ret = sigismember(&old_sigset, num);
184 if ret < 0 {
185 return Err(Error::CompareBlockedSignals(errno::Error::last()));
186 } else if ret > 0 {
187 return Err(Error::SignalAlreadyBlocked(num));
188 }
189 }
190 Ok(())
191 }
192
193 /// Unmasks given signal.
unblock_signal(num: c_int) -> SignalResult<()>194 pub fn unblock_signal(num: c_int) -> SignalResult<()> {
195 let sigset = create_sigset(&[num]).map_err(Error::CreateSigset)?;
196
197 // Safe - return value is checked.
198 let ret = unsafe { pthread_sigmask(SIG_UNBLOCK, &sigset, null_mut()) };
199 if ret < 0 {
200 return Err(Error::UnblockSignal(errno::Error::last()));
201 }
202 Ok(())
203 }
204
205 /// Clears pending signal.
clear_signal(num: c_int) -> SignalResult<()>206 pub fn clear_signal(num: c_int) -> SignalResult<()> {
207 let sigset = create_sigset(&[num]).map_err(Error::CreateSigset)?;
208
209 while {
210 // This is safe as we are rigorously checking return values
211 // of libc calls.
212 unsafe {
213 let mut siginfo: siginfo_t = mem::zeroed();
214 let ts = timespec {
215 tv_sec: 0,
216 tv_nsec: 0,
217 };
218 // Attempt to consume one instance of pending signal. If signal
219 // is not pending, the call will fail with EAGAIN or EINTR.
220 let ret = sigtimedwait(&sigset, &mut siginfo, &ts);
221 if ret < 0 {
222 let e = errno::Error::last();
223 match e.errno() {
224 EAGAIN | EINTR => {}
225 _ => {
226 return Err(Error::ClearWaitPending(errno::Error::last()));
227 }
228 }
229 }
230
231 // This sigset will be actually filled with `sigpending` call.
232 let mut chkset: sigset_t = mem::zeroed();
233 // See if more instances of the signal are pending.
234 let ret = sigpending(&mut chkset);
235 if ret < 0 {
236 return Err(Error::ClearGetPending(errno::Error::last()));
237 }
238
239 let ret = sigismember(&chkset, num);
240 if ret < 0 {
241 return Err(Error::ClearCheckPending(errno::Error::last()));
242 }
243
244 // This is do-while loop condition.
245 ret != 0
246 }
247 } {}
248
249 Ok(())
250 }
251
252 /// Trait for threads that can be signalled via `pthread_kill`.
253 ///
254 /// Note that this is only useful for signals between SIGRTMIN and SIGRTMAX because these are
255 /// guaranteed to not be used by the C runtime.
256 ///
257 /// This is marked unsafe because the implementation of this trait must guarantee that the returned
258 /// pthread_t is valid and has a lifetime at least that of the trait object.
259 pub unsafe trait Killable {
pthread_handle(&self) -> pthread_t260 fn pthread_handle(&self) -> pthread_t;
261
262 /// Sends the signal `num` to this killable thread.
263 ///
264 /// The value of `num` must be within [`SIGRTMIN`, `SIGRTMAX`] range.
kill(&self, num: c_int) -> errno::Result<()>265 fn kill(&self, num: c_int) -> errno::Result<()> {
266 if !valid_signal_num(num) {
267 return Err(errno::Error::new(EINVAL));
268 }
269
270 // Safe because we ensure we are using a valid pthread handle, a valid signal number, and
271 // check the return result.
272 let ret = unsafe { pthread_kill(self.pthread_handle(), num) };
273 if ret < 0 {
274 return errno_result();
275 }
276 Ok(())
277 }
278 }
279
280 // Safe because we fulfill our contract of returning a genuine pthread handle.
281 unsafe impl<T> Killable for JoinHandle<T> {
pthread_handle(&self) -> pthread_t282 fn pthread_handle(&self) -> pthread_t {
283 self.as_pthread_t()
284 }
285 }
286