summaryrefslogtreecommitdiffstats
path: root/vendor/signal-hook/src/iterator/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/signal-hook/src/iterator/mod.rs')
-rw-r--r--vendor/signal-hook/src/iterator/mod.rs323
1 files changed, 323 insertions, 0 deletions
diff --git a/vendor/signal-hook/src/iterator/mod.rs b/vendor/signal-hook/src/iterator/mod.rs
new file mode 100644
index 000000000..b4bfec4e6
--- /dev/null
+++ b/vendor/signal-hook/src/iterator/mod.rs
@@ -0,0 +1,323 @@
+//! An iterator over incoming signals.
+//!
+//! This provides a higher abstraction over the signals, providing
+//! the [`SignalsInfo`] structure which is able to iterate over the
+//! incoming signals. The structure is parametrized by an
+//! [`Exfiltrator`][self::exfiltrator::Exfiltrator], which specifies what information is returned
+//! for each delivered signal. Note that some exfiltrators are behind a feature flag.
+//!
+//! The [`Signals`] is a type alias for the common case when it is enough to get the signal number.
+//!
+//! This module (and everything in it) is turned by the `iterator` feature. It is **on** by
+//! default, the possibility to turn off is mostly possible for very special purposes (compiling on
+//! `<rustc-1.36`, minimizing the amount of code compiled, …). In a sense, this is the highest
+//! level abstraction of the crate and the API expected to be used by most of the people.
+//!
+//! # Examples
+//!
+//! ```rust
+//! extern crate libc;
+//! extern crate signal_hook;
+//!
+//! use std::io::Error;
+//!
+//! use signal_hook::consts::signal::*;
+//! use signal_hook::iterator::Signals;
+//!
+//! fn main() -> Result<(), Error> {
+//! let mut signals = Signals::new(&[
+//! SIGHUP,
+//! SIGTERM,
+//! SIGINT,
+//! SIGQUIT,
+//! # SIGUSR1,
+//! ])?;
+//! # // A trick to terminate the example when run as doc-test. Not part of the real code.
+//! # signal_hook::low_level::raise(SIGUSR1).unwrap();
+//! 'outer: loop {
+//! // Pick up signals that arrived since last time
+//! for signal in signals.pending() {
+//! match signal as libc::c_int {
+//! SIGHUP => {
+//! // Reload configuration
+//! // Reopen the log file
+//! }
+//! SIGTERM | SIGINT | SIGQUIT => {
+//! break 'outer;
+//! },
+//! # SIGUSR1 => return Ok(()),
+//! _ => unreachable!(),
+//! }
+//! }
+//! // Do some bit of work ‒ something with upper limit on waiting, so we don't block
+//! // forever with a SIGTERM already waiting.
+//! }
+//! println!("Terminating. Bye bye");
+//! Ok(())
+//! }
+//! ```
+
+pub mod backend;
+pub mod exfiltrator;
+
+use std::borrow::Borrow;
+use std::fmt::{Debug, Formatter, Result as FmtResult};
+use std::io::{Error, ErrorKind, Read};
+use std::os::unix::net::UnixStream;
+
+use libc::{self, c_int};
+
+pub use self::backend::{Handle, Pending};
+use self::backend::{PollResult, RefSignalIterator, SignalDelivery};
+use self::exfiltrator::{Exfiltrator, SignalOnly};
+
+/// The main structure of the module, representing interest in some signals.
+///
+/// Unlike the helpers in other modules, this registers the signals when created and unregisters
+/// them on drop. It provides the pending signals during its lifetime, either in batches or as an
+/// infinite iterator.
+///
+/// Most users will want to use it through the [`Signals`] type alias for simplicity.
+///
+/// # Multiple threads
+///
+/// Instances of this struct can be [sent][std::marker::Send] to other threads. In a multithreaded
+/// application this can be used to dedicate a separate thread for signal handling. In this case
+/// you should get a [`Handle`] using the [`handle`][Signals::handle] method before sending the
+/// `Signals` instance to a background thread. With the handle you will be able to shut down the
+/// background thread later, or to operatively add more signals.
+///
+/// The controller handle can be shared between as many threads as you like using its
+/// [`clone`][Handle::clone] method.
+///
+/// # Exfiltrators
+///
+/// The [`SignalOnly]` provides only the signal number. There are further exfiltrators available in
+/// the [`exfiltrator`] module. Note that some of them are behind feature flags that need to be
+/// enabled.
+///
+/// # Examples
+///
+/// ```rust
+/// # extern crate signal_hook;
+/// #
+/// # use std::io::Error;
+/// # use std::thread;
+/// use signal_hook::consts::signal::*;
+/// use signal_hook::iterator::Signals;
+///
+/// #
+/// # fn main() -> Result<(), Error> {
+/// let mut signals = Signals::new(&[SIGUSR1, SIGUSR2])?;
+/// let handle = signals.handle();
+/// let thread = thread::spawn(move || {
+/// for signal in &mut signals {
+/// match signal {
+/// SIGUSR1 => {},
+/// SIGUSR2 => {},
+/// _ => unreachable!(),
+/// }
+/// }
+/// });
+///
+/// // Some time later...
+/// handle.close();
+/// thread.join().unwrap();
+/// # Ok(())
+/// # }
+/// ```
+pub struct SignalsInfo<E: Exfiltrator = SignalOnly>(SignalDelivery<UnixStream, E>);
+
+impl<E: Exfiltrator> SignalsInfo<E> {
+ /// Creates the `Signals` structure.
+ ///
+ /// This registers all the signals listed. The same restrictions (panics, errors) apply as
+ /// for the [`Handle::add_signal`] method.
+ pub fn new<I, S>(signals: I) -> Result<Self, Error>
+ where
+ I: IntoIterator<Item = S>,
+ S: Borrow<c_int>,
+ E: Default,
+ {
+ Self::with_exfiltrator(signals, E::default())
+ }
+
+ /// An advanced constructor with explicit [`Exfiltrator`].
+ pub fn with_exfiltrator<I, S>(signals: I, exfiltrator: E) -> Result<Self, Error>
+ where
+ I: IntoIterator<Item = S>,
+ S: Borrow<c_int>,
+ {
+ let (read, write) = UnixStream::pair()?;
+ Ok(SignalsInfo(SignalDelivery::with_pipe(
+ read,
+ write,
+ exfiltrator,
+ signals,
+ )?))
+ }
+
+ /// Registers another signal to the set watched by this [`Signals`] instance.
+ ///
+ /// The same restrictions (panics, errors) apply as for the [`Handle::add_signal`]
+ /// method.
+ pub fn add_signal(&self, signal: c_int) -> Result<(), Error> {
+ self.handle().add_signal(signal)
+ }
+
+ /// Returns an iterator of already received signals.
+ ///
+ /// This returns an iterator over all the signal numbers of the signals received since last
+ /// time they were read (out of the set registered by this `Signals` instance). Note that they
+ /// are returned in arbitrary order and a signal instance may returned only once even if it was
+ /// received multiple times.
+ ///
+ /// This method returns immediately (does not block) and may produce an empty iterator if there
+ /// are no signals ready.
+ pub fn pending(&mut self) -> Pending<E> {
+ self.0.pending()
+ }
+
+ /// Block until the stream contains some bytes.
+ ///
+ /// Returns true if it was possible to read a byte and false otherwise.
+ fn has_signals(read: &mut UnixStream) -> Result<bool, Error> {
+ loop {
+ match read.read(&mut [0u8]) {
+ Ok(num_read) => break Ok(num_read > 0),
+ // If we get an EINTR error it is fine to retry reading from the stream.
+ // Otherwise we should pass on the error to the caller.
+ Err(error) => {
+ if error.kind() != ErrorKind::Interrupted {
+ break Err(error);
+ }
+ }
+ }
+ }
+ }
+
+ /// Waits for some signals to be available and returns an iterator.
+ ///
+ /// This is similar to [`pending`][SignalsInfo::pending]. If there are no signals available, it
+ /// tries to wait for some to arrive. However, due to implementation details, this still can
+ /// produce an empty iterator.
+ ///
+ /// This can block for arbitrary long time. If the [`Handle::close`] method is used in
+ /// another thread this method will return immediately.
+ ///
+ /// Note that the blocking is done in this method, not in the iterator.
+ pub fn wait(&mut self) -> Pending<E> {
+ match self.0.poll_pending(&mut Self::has_signals) {
+ Ok(Some(pending)) => pending,
+ // Because of the blocking has_signals method the poll_pending method
+ // only returns None if the instance is closed. But we want to return
+ // a possibly empty pending object anyway.
+ Ok(None) => self.pending(),
+ // Users can't manipulate the internal file descriptors and the way we use them
+ // shouldn't produce any errors. So it is OK to panic.
+ Err(error) => panic!("Unexpected error: {}", error),
+ }
+ }
+
+ /// Is it closed?
+ ///
+ /// See [`close`][Handle::close].
+ pub fn is_closed(&self) -> bool {
+ self.handle().is_closed()
+ }
+
+ /// Get an infinite iterator over arriving signals.
+ ///
+ /// The iterator's `next()` blocks as necessary to wait for signals to arrive. This is adequate
+ /// if you want to designate a thread solely to handling signals. If multiple signals come at
+ /// the same time (between two values produced by the iterator), they will be returned in
+ /// arbitrary order. Multiple instances of the same signal may be collated.
+ ///
+ /// This is also the iterator returned by `IntoIterator` implementation on `&mut Signals`.
+ ///
+ /// This iterator terminates only if explicitly [closed][Handle::close].
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # extern crate libc;
+ /// # extern crate signal_hook;
+ /// #
+ /// # use std::io::Error;
+ /// # use std::thread;
+ /// #
+ /// use signal_hook::consts::signal::*;
+ /// use signal_hook::iterator::Signals;
+ ///
+ /// # fn main() -> Result<(), Error> {
+ /// let mut signals = Signals::new(&[SIGUSR1, SIGUSR2])?;
+ /// let handle = signals.handle();
+ /// thread::spawn(move || {
+ /// for signal in signals.forever() {
+ /// match signal {
+ /// SIGUSR1 => {},
+ /// SIGUSR2 => {},
+ /// _ => unreachable!(),
+ /// }
+ /// }
+ /// });
+ /// handle.close();
+ /// # Ok(())
+ /// # }
+ /// ```
+ pub fn forever(&mut self) -> Forever<E> {
+ Forever(RefSignalIterator::new(&mut self.0))
+ }
+
+ /// Get a shareable handle to a [`Handle`] for this instance.
+ ///
+ /// This can be used to add further signals or close the [`Signals`] instance.
+ pub fn handle(&self) -> Handle {
+ self.0.handle()
+ }
+}
+
+impl<E> Debug for SignalsInfo<E>
+where
+ E: Debug + Exfiltrator,
+ E::Storage: Debug,
+{
+ fn fmt(&self, fmt: &mut Formatter) -> FmtResult {
+ fmt.debug_tuple("Signals").field(&self.0).finish()
+ }
+}
+
+impl<'a, E: Exfiltrator> IntoIterator for &'a mut SignalsInfo<E> {
+ type Item = E::Output;
+ type IntoIter = Forever<'a, E>;
+ fn into_iter(self) -> Self::IntoIter {
+ self.forever()
+ }
+}
+
+/// An infinit iterator of arriving signals.
+pub struct Forever<'a, E: Exfiltrator>(RefSignalIterator<'a, UnixStream, E>);
+
+impl<'a, E: Exfiltrator> Iterator for Forever<'a, E> {
+ type Item = E::Output;
+
+ fn next(&mut self) -> Option<E::Output> {
+ match self.0.poll_signal(&mut SignalsInfo::<E>::has_signals) {
+ PollResult::Signal(result) => Some(result),
+ PollResult::Closed => None,
+ PollResult::Pending => unreachable!(
+ "Because of the blocking has_signals method the \
+ poll_signal method never returns Poll::Pending but blocks until a signal arrived"
+ ),
+ // Users can't manipulate the internal file descriptors and the way we use them
+ // shouldn't produce any errors. So it is OK to panic.
+ PollResult::Err(error) => panic!("Unexpected error: {}", error),
+ }
+ }
+}
+
+/// A type alias for an iterator returning just the signal numbers.
+///
+/// This is the simplified version for most of the use cases. For advanced usages, the
+/// [`SignalsInfo`] with explicit [`Exfiltrator`] type can be used.
+pub type Signals = SignalsInfo<SignalOnly>;