signal_hook_mio/
lib.rs

1#![doc(test(attr(deny(warnings))))]
2#![warn(missing_docs)]
3#![cfg_attr(docsrs, feature(doc_cfg))]
4
5//! A crate offering integration with the MIO runtime.
6//!
7//! There are different sub modules for supporting different MIO
8//! versions. The support for a version must be activated by a
9//! feature flag:
10//!
11//! * `support-v0_6` for sub module [`v0_6`]
12//! * `support-v0_7` for sub module [`v0_7`]
13//! * `support-v0_8` for sub module [`v0_8`]
14//! * `support-v0_8` for sub module [`v1_0`]
15//!
16//! See the specific sub modules for usage examples.
17
18#[cfg(any(
19    feature = "support-v0_6",
20    feature = "support-v0_7",
21    feature = "support-v0_8",
22    feature = "support-v1_0"
23))]
24macro_rules! implement_signals_with_pipe {
25    ($pipe:path) => {
26        use std::borrow::Borrow;
27        use std::io::Error;
28
29        use signal_hook::iterator::backend::{self, SignalDelivery};
30        use signal_hook::iterator::exfiltrator::{Exfiltrator, SignalOnly};
31
32        use $pipe as Pipe;
33
34        use libc::c_int;
35
36        /// A struct which mimics [`signal_hook::iterator::SignalsInfo`]
37        /// but also allows usage together with MIO runtime.
38        pub struct SignalsInfo<E: Exfiltrator = SignalOnly>(SignalDelivery<Pipe, E>);
39
40        pub use backend::Pending;
41
42        impl<E: Exfiltrator> SignalsInfo<E> {
43            /// Create a `Signals` instance.
44            ///
45            /// This registers all the signals listed. The same restrictions (panics, errors) apply
46            /// as with [`Handle::add_signal`][backend::Handle::add_signal].
47            pub fn new<I, S>(signals: I) -> Result<Self, Error>
48            where
49                I: IntoIterator<Item = S>,
50                S: Borrow<c_int>,
51                E: Default,
52            {
53                Self::with_exfiltrator(signals, E::default())
54            }
55
56            /// A constructor with specifying an exfiltrator to pass information out of the signal
57            /// handlers.
58            pub fn with_exfiltrator<I, S>(signals: I, exfiltrator: E) -> Result<Self, Error>
59            where
60                I: IntoIterator<Item = S>,
61                S: Borrow<c_int>,
62            {
63                let (read, write) = Pipe::pair()?;
64                let delivery = SignalDelivery::with_pipe(read, write, exfiltrator, signals)?;
65                Ok(Self(delivery))
66            }
67
68            /// Registers another signal to the set watched by this [`Signals`] instance.
69            ///
70            /// The same restrictions (panics, errors) apply as with
71            /// [`Handle::add_signal`][backend::Handle::add_signal].
72            pub fn add_signal(&self, signal: c_int) -> Result<(), Error> {
73                self.0.handle().add_signal(signal)
74            }
75
76            /// Returns an iterator of already received signals.
77            ///
78            /// This returns an iterator over all the signal numbers of the signals received since last
79            /// time they were read (out of the set registered by this `Signals` instance). Note that they
80            /// are returned in arbitrary order and a signal number is returned only once even if it was
81            /// received multiple times.
82            ///
83            /// This method returns immediately (does not block) and may produce an empty iterator if there
84            /// are no signals ready. So you should register an instance of this struct at an instance of
85            /// [`mio::Poll`] to query for readability of the underlying self pipe.
86            pub fn pending(&mut self) -> Pending<E> {
87                self.0.pending()
88            }
89        }
90
91        /// A simplified signal iterator.
92        ///
93        /// This is the [`SignalsInfo`], but returning only the signal numbers. This is likely the
94        /// one you want to use.
95        pub type Signals = SignalsInfo<SignalOnly>;
96    };
97}
98
99/// A module for integrating signal handling with the MIO 1.0 runtime.
100///
101/// This provides the [`Signals`][v1_0::Signals] struct as an abstraction
102/// which can be used with [`mio::Poll`][mio_1_0::Poll].
103///
104/// # Examples
105///
106/// ```rust
107/// # use mio_1_0 as mio;
108/// use std::io::{Error, ErrorKind};
109///
110/// use signal_hook::consts::signal::*;
111/// use signal_hook_mio::v1_0::Signals;
112///
113/// use mio::{Events, Poll, Interest, Token};
114///
115/// fn main() -> Result<(), Error> {
116///     let mut poll = Poll::new()?;
117///
118///     let mut signals = Signals::new(&[
119///         SIGTERM,
120/// #       SIGUSR1,
121///     ])?;
122///
123///     let signal_token = Token(0);
124///
125///     poll.registry().register(&mut signals, signal_token, Interest::READABLE)?;
126/// #   signal_hook::low_level::raise(SIGUSR1).unwrap(); // Just for terminating the example
127///
128///     let mut events = Events::with_capacity(10);
129///     'outer: loop {
130///         poll.poll(&mut events, None)
131///             .or_else(|e| if e.kind() == ErrorKind::Interrupted {
132///                 // We get interrupt when a signal happens inside poll. That's non-fatal, just
133///                 // retry.
134///                 events.clear();
135///                 Ok(())
136///             } else {
137///                 Err(e)
138///             })?;
139///         for event in events.iter() {
140///             match event.token() {
141///                 Token(0) => {
142///                     for signal in signals.pending() {
143///                         match signal {
144///                             SIGTERM => break 'outer,
145/// #                           SIGUSR1 => return Ok(()),
146///                             _ => unreachable!(),
147///                         }
148///                     }
149///                 },
150///                 _ => unreachable!("Register other sources and match for their tokens here"),
151///             }
152///         }
153///     }
154///
155///     Ok(())
156/// }
157/// ```
158#[cfg(feature = "support-v1_0")]
159pub mod v1_0 {
160    use mio::event::Source;
161    use mio::{Interest, Registry, Token};
162    use mio_1_0 as mio;
163
164    implement_signals_with_pipe!(mio::net::UnixStream);
165
166    impl Source for Signals {
167        fn register(
168            &mut self,
169            registry: &Registry,
170            token: Token,
171            interest: Interest,
172        ) -> Result<(), Error> {
173            self.0.get_read_mut().register(registry, token, interest)
174        }
175
176        fn reregister(
177            &mut self,
178            registry: &Registry,
179            token: Token,
180            interest: Interest,
181        ) -> Result<(), Error> {
182            self.0.get_read_mut().reregister(registry, token, interest)
183        }
184
185        fn deregister(&mut self, registry: &Registry) -> Result<(), Error> {
186            self.0.get_read_mut().deregister(registry)
187        }
188    }
189}
190
191/// A module for integrating signal handling with the MIO 0.8 runtime.
192///
193/// This provides the [`Signals`][v0_8::Signals] struct as an abstraction
194/// which can be used with [`mio::Poll`][mio_0_8::Poll].
195///
196/// # Examples
197///
198/// ```rust
199/// # use mio_0_8 as mio;
200/// use std::io::{Error, ErrorKind};
201///
202/// use signal_hook::consts::signal::*;
203/// use signal_hook_mio::v0_8::Signals;
204///
205/// use mio::{Events, Poll, Interest, Token};
206///
207/// fn main() -> Result<(), Error> {
208///     let mut poll = Poll::new()?;
209///
210///     let mut signals = Signals::new(&[
211///         SIGTERM,
212/// #       SIGUSR1,
213///     ])?;
214///
215///     let signal_token = Token(0);
216///
217///     poll.registry().register(&mut signals, signal_token, Interest::READABLE)?;
218/// #   signal_hook::low_level::raise(SIGUSR1).unwrap(); // Just for terminating the example
219///
220///     let mut events = Events::with_capacity(10);
221///     'outer: loop {
222///         poll.poll(&mut events, None)
223///             .or_else(|e| if e.kind() == ErrorKind::Interrupted {
224///                 // We get interrupt when a signal happens inside poll. That's non-fatal, just
225///                 // retry.
226///                 events.clear();
227///                 Ok(())
228///             } else {
229///                 Err(e)
230///             })?;
231///         for event in events.iter() {
232///             match event.token() {
233///                 Token(0) => {
234///                     for signal in signals.pending() {
235///                         match signal {
236///                             SIGTERM => break 'outer,
237/// #                           SIGUSR1 => return Ok(()),
238///                             _ => unreachable!(),
239///                         }
240///                     }
241///                 },
242///                 _ => unreachable!("Register other sources and match for their tokens here"),
243///             }
244///         }
245///     }
246///
247///     Ok(())
248/// }
249/// ```
250#[cfg(feature = "support-v0_8")]
251pub mod v0_8 {
252    use mio::event::Source;
253    use mio::{Interest, Registry, Token};
254    use mio_0_8 as mio;
255
256    implement_signals_with_pipe!(mio::net::UnixStream);
257
258    impl Source for Signals {
259        fn register(
260            &mut self,
261            registry: &Registry,
262            token: Token,
263            interest: Interest,
264        ) -> Result<(), Error> {
265            self.0.get_read_mut().register(registry, token, interest)
266        }
267
268        fn reregister(
269            &mut self,
270            registry: &Registry,
271            token: Token,
272            interest: Interest,
273        ) -> Result<(), Error> {
274            self.0.get_read_mut().reregister(registry, token, interest)
275        }
276
277        fn deregister(&mut self, registry: &Registry) -> Result<(), Error> {
278            self.0.get_read_mut().deregister(registry)
279        }
280    }
281}
282
283/// A module for integrating signal handling with the MIO 0.7 runtime.
284///
285/// This provides the [`Signals`][v0_7::Signals] struct as an abstraction
286/// which can be used with [`mio::Poll`][mio_0_7::Poll].
287///
288/// # Examples
289///
290/// ```rust
291/// # use mio_0_7 as mio;
292/// use std::io::{Error, ErrorKind};
293///
294/// use signal_hook::consts::signal::*;
295/// use signal_hook_mio::v0_7::Signals;
296///
297/// use mio::{Events, Poll, Interest, Token};
298///
299/// fn main() -> Result<(), Error> {
300///     let mut poll = Poll::new()?;
301///
302///     let mut signals = Signals::new(&[
303///         SIGTERM,
304/// #       SIGUSR1,
305///     ])?;
306///
307///     let signal_token = Token(0);
308///
309///     poll.registry().register(&mut signals, signal_token, Interest::READABLE)?;
310/// #   signal_hook::low_level::raise(SIGUSR1).unwrap(); // Just for terminating the example
311///
312///     let mut events = Events::with_capacity(10);
313///     'outer: loop {
314///         poll.poll(&mut events, None)
315///             .or_else(|e| if e.kind() == ErrorKind::Interrupted {
316///                 // We get interrupt when a signal happens inside poll. That's non-fatal, just
317///                 // retry.
318///                 events.clear();
319///                 Ok(())
320///             } else {
321///                 Err(e)
322///             })?;
323///         for event in events.iter() {
324///             match event.token() {
325///                 Token(0) => {
326///                     for signal in signals.pending() {
327///                         match signal {
328///                             SIGTERM => break 'outer,
329/// #                           SIGUSR1 => return Ok(()),
330///                             _ => unreachable!(),
331///                         }
332///                     }
333///                 },
334///                 _ => unreachable!("Register other sources and match for their tokens here"),
335///             }
336///         }
337///     }
338///
339///     Ok(())
340/// }
341/// ```
342#[cfg(feature = "support-v0_7")]
343pub mod v0_7 {
344    use mio::event::Source;
345    use mio::{Interest, Registry, Token};
346    use mio_0_7 as mio;
347
348    implement_signals_with_pipe!(mio::net::UnixStream);
349
350    impl Source for Signals {
351        fn register(
352            &mut self,
353            registry: &Registry,
354            token: Token,
355            interest: Interest,
356        ) -> Result<(), Error> {
357            self.0.get_read_mut().register(registry, token, interest)
358        }
359
360        fn reregister(
361            &mut self,
362            registry: &Registry,
363            token: Token,
364            interest: Interest,
365        ) -> Result<(), Error> {
366            self.0.get_read_mut().reregister(registry, token, interest)
367        }
368
369        fn deregister(&mut self, registry: &Registry) -> Result<(), Error> {
370            self.0.get_read_mut().deregister(registry)
371        }
372    }
373}
374
375/// A module for integrating signal handling with the MIO 0.6 runtime.
376///
377/// This provides the [`Signals`][v0_6::Signals] struct as an abstraction
378/// which can be used with [`mio::Poll`][mio_0_6::Poll].
379///
380/// # Examples
381///
382/// ```rust
383/// # use mio_0_6 as mio;
384/// use std::io::{Error, ErrorKind};
385///
386/// use signal_hook::consts::signal::*;
387/// use signal_hook_mio::v0_6::Signals;
388///
389/// use mio::{Events, Poll, PollOpt, Ready, Token};
390///
391/// fn main() -> Result<(), Error> {
392///     let poll = Poll::new()?;
393///
394///     let mut signals = Signals::new(&[
395///         SIGTERM,
396/// #       SIGUSR1,
397///     ])?;
398///
399///     let signal_token = Token(0);
400///
401///     poll.register(&mut signals, signal_token, Ready::readable(), PollOpt::level())?;
402/// #   signal_hook::low_level::raise(SIGUSR1).unwrap(); // Just for terminating the example
403///
404///     let mut events = Events::with_capacity(10);
405///     'outer: loop {
406///         poll.poll(&mut events, None)
407///             .or_else(|e| if e.kind() == ErrorKind::Interrupted {
408///                 // We get interrupt when a signal happens inside poll. That's non-fatal, just
409///                 // retry.
410///                 events.clear();
411///                 Ok(0)
412///             } else {
413///                 Err(e)
414///             })?;
415///         for event in events.iter() {
416///             match event.token() {
417///                 Token(0) => {
418///                     for signal in signals.pending() {
419///                         match signal {
420///                             SIGTERM => break 'outer,
421/// #                           SIGUSR1 => return Ok(()),
422///                             _ => unreachable!(),
423///                         }
424///                     }
425///                 },
426///                 _ => unreachable!("Register other sources and match for their tokens here"),
427///             }
428///         }
429///     }
430///
431///     Ok(())
432/// }
433/// ```
434#[cfg(feature = "support-v0_6")]
435pub mod v0_6 {
436
437    use mio::event::Evented;
438    use mio::{Poll, PollOpt, Ready, Token};
439    use mio_0_6 as mio;
440
441    implement_signals_with_pipe!(mio_uds::UnixStream);
442
443    impl Evented for Signals {
444        fn register(
445            &self,
446            poll: &Poll,
447            token: Token,
448            interest: Ready,
449            opts: PollOpt,
450        ) -> Result<(), Error> {
451            self.0.get_read().register(poll, token, interest, opts)
452        }
453
454        fn reregister(
455            &self,
456            poll: &Poll,
457            token: Token,
458            interest: Ready,
459            opts: PollOpt,
460        ) -> Result<(), Error> {
461            self.0.get_read().reregister(poll, token, interest, opts)
462        }
463
464        fn deregister(&self, poll: &Poll) -> Result<(), Error> {
465            self.0.get_read().deregister(poll)
466        }
467    }
468}