signal_hook_async_std/lib.rs
1#![doc(test(attr(deny(warnings))))]
2#![warn(missing_docs)]
3#![cfg_attr(docsrs, feature(doc_cfg))]
4
5//! A module for integrating signal handling with the async-std runtime.
6//!
7//! This provides the [`Signals`] struct which acts as a
8//! [`Stream`] of signals.
9//!
10//! # Example
11//!
12//! ```rust
13//! use std::io::Error;
14//!
15//! use async_std::prelude::*;
16//!
17//! use signal_hook::consts::signal::*;
18//! use signal_hook_async_std::Signals;
19//!
20//! async fn handle_signals(mut signals: Signals) {
21//! while let Some(signal) = signals.next().await {
22//! match signal {
23//! SIGHUP => {
24//! // Reload configuration
25//! // Reopen the log file
26//! }
27//! SIGTERM | SIGINT | SIGQUIT => {
28//! // Shutdown the system;
29//! },
30//! _ => unreachable!(),
31//! }
32//! }
33//! }
34//!
35//! #[async_std::main]
36//! async fn main() -> Result<(), Error> {
37//! let signals = Signals::new(&[SIGHUP, SIGTERM, SIGINT, SIGQUIT])?;
38//! let handle = signals.handle();
39//!
40//! let signals_task = async_std::task::spawn(handle_signals(signals));
41//!
42//! // Execute your main program logic
43//!
44//! // Terminate the signal stream.
45//! handle.close();
46//! signals_task.await;
47//!
48//! Ok(())
49//! }
50//! ```
51
52use std::borrow::Borrow;
53use std::io::Error;
54use std::os::unix::net::UnixStream;
55use std::pin::Pin;
56use std::task::{Context, Poll};
57
58use libc::c_int;
59
60pub use signal_hook::iterator::backend::Handle;
61use signal_hook::iterator::backend::{OwningSignalIterator, PollResult, SignalDelivery};
62use signal_hook::iterator::exfiltrator::{Exfiltrator, SignalOnly};
63
64use async_io::Async;
65use futures_lite::io::AsyncRead;
66use futures_lite::stream::Stream;
67
68/// An asynchronous [`Stream`] of arriving signals.
69///
70/// The stream doesn't return the signals in the order they were recieved by
71/// the process and may merge signals received multiple times.
72pub struct SignalsInfo<E: Exfiltrator = SignalOnly>(OwningSignalIterator<Async<UnixStream>, E>);
73
74impl<E: Exfiltrator> SignalsInfo<E> {
75 /// Create a `Signals` instance.
76 ///
77 /// This registers all the signals listed. The same restrictions (panics, errors) apply
78 /// as with [`Handle::add_signal`].
79 pub fn new<I, S>(signals: I) -> Result<Self, Error>
80 where
81 I: IntoIterator<Item = S>,
82 S: Borrow<c_int>,
83 E: Default,
84 {
85 Self::with_exfiltrator(signals, E::default())
86 }
87
88 /// A constructor with explicit exfiltrator.
89 pub fn with_exfiltrator<I, S>(signals: I, exfiltrator: E) -> Result<Self, Error>
90 where
91 I: IntoIterator<Item = S>,
92 S: Borrow<c_int>,
93 {
94 let (read, write) = Async::<UnixStream>::pair()?;
95 let inner = SignalDelivery::with_pipe(read, write, exfiltrator, signals)?;
96 Ok(Self(OwningSignalIterator::new(inner)))
97 }
98
99 /// Get a shareable [`Handle`] for this `Signals` instance.
100 ///
101 /// This can be used to add further signals or close the [`Signals`] instance
102 /// which terminates the whole signal stream.
103 pub fn handle(&self) -> Handle {
104 self.0.handle()
105 }
106}
107
108impl<E: Exfiltrator> SignalsInfo<E> {
109 fn has_signals(read: &mut Async<UnixStream>, ctx: &mut Context<'_>) -> Result<bool, Error> {
110 match Pin::new(read).poll_read(ctx, &mut [0u8]) {
111 Poll::Pending => Ok(false),
112 Poll::Ready(Ok(num_read)) => Ok(num_read > 0),
113 Poll::Ready(Err(error)) => Err(error),
114 }
115 }
116}
117
118impl<E: Exfiltrator> Stream for SignalsInfo<E> {
119 type Item = E::Output;
120
121 fn poll_next(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
122 match self.0.poll_signal(&mut |read| Self::has_signals(read, ctx)) {
123 PollResult::Signal(sig) => Poll::Ready(Some(sig)),
124 PollResult::Closed => Poll::Ready(None),
125 PollResult::Pending => Poll::Pending,
126 PollResult::Err(error) => panic!("Unexpected error: {}", error),
127 }
128 }
129}
130
131/// Simplified version of the signals stream.
132///
133/// This one simply returns the signal numbers, while [`SignalsInfo`] can provide additional
134/// information.
135pub type Signals = SignalsInfo<SignalOnly>;