signal_hook/iterator/
mod.rs

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