• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
new<I, S>(signals: I) -> Result<Self, Error> where I: IntoIterator<Item = S>, S: Borrow<c_int>, E: Default,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`].
with_exfiltrator<I, S>(signals: I, exfiltrator: E) -> Result<Self, Error> where I: IntoIterator<Item = S>, S: Borrow<c_int>,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.
add_signal(&self, signal: c_int) -> Result<(), Error>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.
pending(&mut self) -> Pending<E>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.
has_signals(read: &mut UnixStream) -> Result<bool, Error>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.
wait(&mut self) -> Pending<E>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].
is_closed(&self) -> bool225     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     /// ```
forever(&mut self) -> Forever<E>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.
handle(&self) -> Handle275     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 {
fmt(&self, fmt: &mut Formatter) -> FmtResult285     fn fmt(&self, fmt: &mut Formatter) -> FmtResult {
286         fmt.debug_tuple("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>;
into_iter(self) -> Self::IntoIter293     fn into_iter(self) -> Self::IntoIter {
294         self.forever()
295     }
296 }
297 
298 /// An infinit 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 
next(&mut self) -> Option<E::Output>304     fn next(&mut self) -> Option<E::Output> {
305         match self.0.poll_signal(&mut SignalsInfo::<E>::has_signals) {
306             PollResult::Signal(result) => Some(result),
307             PollResult::Closed => None,
308             PollResult::Pending => unreachable!(
309                 "Because of the blocking has_signals method the \
310                 poll_signal method never returns Poll::Pending but blocks until a signal arrived"
311             ),
312             // Users can't manipulate the internal file descriptors and the way we use them
313             // shouldn't produce any errors. So it is OK to panic.
314             PollResult::Err(error) => panic!("Unexpected error: {}", error),
315         }
316     }
317 }
318 
319 /// A type alias for an iterator returning just the signal numbers.
320 ///
321 /// This is the simplified version for most of the use cases. For advanced usages, the
322 /// [`SignalsInfo`] with explicit [`Exfiltrator`] type can be used.
323 pub type Signals = SignalsInfo<SignalOnly>;
324