1 | //! An iterator over incoming signals. |
2 | //! |
3 | //! This provides a higher abstraction over the signals, providing |
4 | //! the [`SignalsInfo`] structure which is able to iterate over the |
5 | //! incoming signals. The structure is parametrized by an |
6 | //! [`Exfiltrator`][self::exfiltrator::Exfiltrator], which specifies what information is returned |
7 | //! for each delivered signal. Note that some exfiltrators are behind a feature flag. |
8 | //! |
9 | //! The [`Signals`] is a type alias for the common case when it is enough to get the signal number. |
10 | //! |
11 | //! This module (and everything in it) is turned by the `iterator` feature. It is **on** by |
12 | //! default, the possibility to turn off is mostly possible for very special purposes (compiling on |
13 | //! `<rustc-1.36`, minimizing the amount of code compiled, …). In a sense, this is the highest |
14 | //! level abstraction of the crate and the API expected to be used by most of the people. |
15 | //! |
16 | //! # Examples |
17 | //! |
18 | //! ```rust |
19 | //! extern crate libc; |
20 | //! extern crate signal_hook; |
21 | //! |
22 | //! use std::io::Error; |
23 | //! |
24 | //! use signal_hook::consts::signal::*; |
25 | //! use signal_hook::iterator::Signals; |
26 | //! |
27 | //! fn main() -> Result<(), Error> { |
28 | //! let mut signals = Signals::new(&[ |
29 | //! SIGHUP, |
30 | //! SIGTERM, |
31 | //! SIGINT, |
32 | //! SIGQUIT, |
33 | //! # SIGUSR1, |
34 | //! ])?; |
35 | //! # // A trick to terminate the example when run as doc-test. Not part of the real code. |
36 | //! # signal_hook::low_level::raise(SIGUSR1).unwrap(); |
37 | //! 'outer: loop { |
38 | //! // Pick up signals that arrived since last time |
39 | //! for signal in signals.pending() { |
40 | //! match signal as libc::c_int { |
41 | //! SIGHUP => { |
42 | //! // Reload configuration |
43 | //! // Reopen the log file |
44 | //! } |
45 | //! SIGTERM | SIGINT | SIGQUIT => { |
46 | //! break 'outer; |
47 | //! }, |
48 | //! # SIGUSR1 => return Ok(()), |
49 | //! _ => unreachable!(), |
50 | //! } |
51 | //! } |
52 | //! // Do some bit of work ‒ something with upper limit on waiting, so we don't block |
53 | //! // forever with a SIGTERM already waiting. |
54 | //! } |
55 | //! println!("Terminating. Bye bye" ); |
56 | //! Ok(()) |
57 | //! } |
58 | //! ``` |
59 | |
60 | pub mod backend; |
61 | pub mod exfiltrator; |
62 | |
63 | use std::borrow::Borrow; |
64 | use std::fmt::{Debug, Formatter, Result as FmtResult}; |
65 | use std::io::{Error, ErrorKind, Read}; |
66 | use std::os::unix::net::UnixStream; |
67 | |
68 | use libc::{self, c_int}; |
69 | |
70 | pub use self::backend::{Handle, Pending}; |
71 | use self::backend::{PollResult, RefSignalIterator, SignalDelivery}; |
72 | use self::exfiltrator::{Exfiltrator, SignalOnly}; |
73 | |
74 | /// The main structure of the module, representing interest in some signals. |
75 | /// |
76 | /// Unlike the helpers in other modules, this registers the signals when created and unregisters |
77 | /// them on drop. It provides the pending signals during its lifetime, either in batches or as an |
78 | /// infinite iterator. |
79 | /// |
80 | /// Most users will want to use it through the [`Signals`] type alias for simplicity. |
81 | /// |
82 | /// # Multiple threads |
83 | /// |
84 | /// Instances of this struct can be [sent][std::marker::Send] to other threads. In a multithreaded |
85 | /// application this can be used to dedicate a separate thread for signal handling. In this case |
86 | /// you should get a [`Handle`] using the [`handle`][Signals::handle] method before sending the |
87 | /// `Signals` instance to a background thread. With the handle you will be able to shut down the |
88 | /// background thread later, or to operatively add more signals. |
89 | /// |
90 | /// The controller handle can be shared between as many threads as you like using its |
91 | /// [`clone`][Handle::clone] method. |
92 | /// |
93 | /// # Exfiltrators |
94 | /// |
95 | /// The [`SignalOnly]` provides only the signal number. There are further exfiltrators available in |
96 | /// the [`exfiltrator`] module. Note that some of them are behind feature flags that need to be |
97 | /// enabled. |
98 | /// |
99 | /// # Examples |
100 | /// |
101 | /// ```rust |
102 | /// # extern crate signal_hook; |
103 | /// # |
104 | /// # use std::io::Error; |
105 | /// # use std::thread; |
106 | /// use signal_hook::consts::signal::*; |
107 | /// use signal_hook::iterator::Signals; |
108 | /// |
109 | /// # |
110 | /// # fn main() -> Result<(), Error> { |
111 | /// let mut signals = Signals::new(&[SIGUSR1, SIGUSR2])?; |
112 | /// let handle = signals.handle(); |
113 | /// let thread = thread::spawn(move || { |
114 | /// for signal in &mut signals { |
115 | /// match signal { |
116 | /// SIGUSR1 => {}, |
117 | /// SIGUSR2 => {}, |
118 | /// _ => unreachable!(), |
119 | /// } |
120 | /// } |
121 | /// }); |
122 | /// |
123 | /// // Some time later... |
124 | /// handle.close(); |
125 | /// thread.join().unwrap(); |
126 | /// # Ok(()) |
127 | /// # } |
128 | /// ``` |
129 | pub struct SignalsInfo<E: Exfiltrator = SignalOnly>(SignalDelivery<UnixStream, E>); |
130 | |
131 | impl<E: Exfiltrator> SignalsInfo<E> { |
132 | /// Creates the `Signals` structure. |
133 | /// |
134 | /// This registers all the signals listed. The same restrictions (panics, errors) apply as |
135 | /// for the [`Handle::add_signal`] method. |
136 | pub fn new<I, S>(signals: I) -> Result<Self, Error> |
137 | where |
138 | I: IntoIterator<Item = S>, |
139 | S: Borrow<c_int>, |
140 | E: Default, |
141 | { |
142 | Self::with_exfiltrator(signals, E::default()) |
143 | } |
144 | |
145 | /// An advanced constructor with explicit [`Exfiltrator`]. |
146 | pub fn with_exfiltrator<I, S>(signals: I, exfiltrator: E) -> Result<Self, Error> |
147 | where |
148 | I: IntoIterator<Item = S>, |
149 | S: Borrow<c_int>, |
150 | { |
151 | let (read, write) = UnixStream::pair()?; |
152 | Ok(SignalsInfo(SignalDelivery::with_pipe( |
153 | read, |
154 | write, |
155 | exfiltrator, |
156 | signals, |
157 | )?)) |
158 | } |
159 | |
160 | /// Registers another signal to the set watched by this [`Signals`] instance. |
161 | /// |
162 | /// The same restrictions (panics, errors) apply as for the [`Handle::add_signal`] |
163 | /// method. |
164 | pub fn add_signal(&self, signal: c_int) -> Result<(), Error> { |
165 | self.handle().add_signal(signal) |
166 | } |
167 | |
168 | /// Returns an iterator of already received signals. |
169 | /// |
170 | /// This returns an iterator over all the signal numbers of the signals received since last |
171 | /// time they were read (out of the set registered by this `Signals` instance). Note that they |
172 | /// are returned in arbitrary order and a signal instance may returned only once even if it was |
173 | /// received multiple times. |
174 | /// |
175 | /// This method returns immediately (does not block) and may produce an empty iterator if there |
176 | /// are no signals ready. |
177 | pub fn pending(&mut self) -> Pending<E> { |
178 | self.0.pending() |
179 | } |
180 | |
181 | /// Block until the stream contains some bytes. |
182 | /// |
183 | /// Returns true if it was possible to read a byte and false otherwise. |
184 | fn has_signals(read: &mut UnixStream) -> Result<bool, Error> { |
185 | loop { |
186 | match read.read(&mut [0u8]) { |
187 | Ok(num_read) => break Ok(num_read > 0), |
188 | // If we get an EINTR error it is fine to retry reading from the stream. |
189 | // Otherwise we should pass on the error to the caller. |
190 | Err(error) => { |
191 | if error.kind() != ErrorKind::Interrupted { |
192 | break Err(error); |
193 | } |
194 | } |
195 | } |
196 | } |
197 | } |
198 | |
199 | /// Waits for some signals to be available and returns an iterator. |
200 | /// |
201 | /// This is similar to [`pending`][SignalsInfo::pending]. If there are no signals available, it |
202 | /// tries to wait for some to arrive. However, due to implementation details, this still can |
203 | /// produce an empty iterator. |
204 | /// |
205 | /// This can block for arbitrary long time. If the [`Handle::close`] method is used in |
206 | /// another thread this method will return immediately. |
207 | /// |
208 | /// Note that the blocking is done in this method, not in the iterator. |
209 | pub fn wait(&mut self) -> Pending<E> { |
210 | match self.0.poll_pending(&mut Self::has_signals) { |
211 | Ok(Some(pending)) => pending, |
212 | // Because of the blocking has_signals method the poll_pending method |
213 | // only returns None if the instance is closed. But we want to return |
214 | // a possibly empty pending object anyway. |
215 | Ok(None) => self.pending(), |
216 | // Users can't manipulate the internal file descriptors and the way we use them |
217 | // shouldn't produce any errors. So it is OK to panic. |
218 | Err(error) => panic!("Unexpected error: {}" , error), |
219 | } |
220 | } |
221 | |
222 | /// Is it closed? |
223 | /// |
224 | /// See [`close`][Handle::close]. |
225 | pub fn is_closed(&self) -> bool { |
226 | self.handle().is_closed() |
227 | } |
228 | |
229 | /// Get an infinite iterator over arriving signals. |
230 | /// |
231 | /// The iterator's `next()` blocks as necessary to wait for signals to arrive. This is adequate |
232 | /// if you want to designate a thread solely to handling signals. If multiple signals come at |
233 | /// the same time (between two values produced by the iterator), they will be returned in |
234 | /// arbitrary order. Multiple instances of the same signal may be collated. |
235 | /// |
236 | /// This is also the iterator returned by `IntoIterator` implementation on `&mut Signals`. |
237 | /// |
238 | /// This iterator terminates only if explicitly [closed][Handle::close]. |
239 | /// |
240 | /// # Examples |
241 | /// |
242 | /// ```rust |
243 | /// # extern crate libc; |
244 | /// # extern crate signal_hook; |
245 | /// # |
246 | /// # use std::io::Error; |
247 | /// # use std::thread; |
248 | /// # |
249 | /// use signal_hook::consts::signal::*; |
250 | /// use signal_hook::iterator::Signals; |
251 | /// |
252 | /// # fn main() -> Result<(), Error> { |
253 | /// let mut signals = Signals::new(&[SIGUSR1, SIGUSR2])?; |
254 | /// let handle = signals.handle(); |
255 | /// thread::spawn(move || { |
256 | /// for signal in signals.forever() { |
257 | /// match signal { |
258 | /// SIGUSR1 => {}, |
259 | /// SIGUSR2 => {}, |
260 | /// _ => unreachable!(), |
261 | /// } |
262 | /// } |
263 | /// }); |
264 | /// handle.close(); |
265 | /// # Ok(()) |
266 | /// # } |
267 | /// ``` |
268 | pub fn forever(&mut self) -> Forever<E> { |
269 | Forever(RefSignalIterator::new(&mut self.0)) |
270 | } |
271 | |
272 | /// Get a shareable handle to a [`Handle`] for this instance. |
273 | /// |
274 | /// This can be used to add further signals or close the [`Signals`] instance. |
275 | pub fn handle(&self) -> Handle { |
276 | self.0.handle() |
277 | } |
278 | } |
279 | |
280 | impl<E> Debug for SignalsInfo<E> |
281 | where |
282 | E: Debug + Exfiltrator, |
283 | E::Storage: Debug, |
284 | { |
285 | fn fmt(&self, fmt: &mut Formatter) -> FmtResult { |
286 | fmt.debug_tuple(name:"Signals" ).field(&self.0).finish() |
287 | } |
288 | } |
289 | |
290 | impl<'a, E: Exfiltrator> IntoIterator for &'a mut SignalsInfo<E> { |
291 | type Item = E::Output; |
292 | type IntoIter = Forever<'a, E>; |
293 | fn into_iter(self) -> Self::IntoIter { |
294 | self.forever() |
295 | } |
296 | } |
297 | |
298 | /// An infinite iterator of arriving signals. |
299 | pub struct Forever<'a, E: Exfiltrator>(RefSignalIterator<'a, UnixStream, E>); |
300 | |
301 | impl<'a, E: Exfiltrator> Iterator for Forever<'a, E> { |
302 | type Item = E::Output; |
303 | |
304 | fn next(&mut self) -> Option<E::Output> { |
305 | loop { |
306 | match self.0.poll_signal(&mut SignalsInfo::<E>::has_signals) { |
307 | PollResult::Signal(result: ::Output) => break Some(result), |
308 | PollResult::Closed => break None, |
309 | // In theory, the poll_signal should not return PollResult::Pending. Nevertheless, |
310 | // there's a race condition - if the other side closes the pipe/socket after |
311 | // checking for it being closed, then the `read` there returns 0 as EOF. That |
312 | // appears as pending here. Next time we should get Closed. |
313 | PollResult::Pending => continue, |
314 | // Users can't manipulate the internal file descriptors and the way we use them |
315 | // shouldn't produce any errors. So it is OK to panic. |
316 | PollResult::Err(error: Error) => panic!("Unexpected error: {}" , error), |
317 | } |
318 | } |
319 | } |
320 | } |
321 | |
322 | /// A type alias for an iterator returning just the signal numbers. |
323 | /// |
324 | /// This is the simplified version for most of the use cases. For advanced usages, the |
325 | /// [`SignalsInfo`] with explicit [`Exfiltrator`] type can be used. |
326 | pub type Signals = SignalsInfo<SignalOnly>; |
327 | |