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