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