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}