actix_server/
signals.rs

1use std::{
2    fmt,
3    future::Future,
4    pin::{pin, Pin},
5    task::{Context, Poll},
6};
7
8use futures_core::future::BoxFuture;
9use tracing::trace;
10
11/// Types of process signals.
12// #[allow(dead_code)]
13#[derive(Debug, Clone, Copy, PartialEq)]
14#[allow(dead_code)] // variants are never constructed on non-unix
15pub(crate) enum SignalKind {
16    /// Cancellation token or channel.
17    Cancel,
18
19    /// OS `SIGINT`.
20    OsInt,
21
22    /// OS `SIGTERM`.
23    OsTerm,
24
25    /// OS `SIGQUIT`.
26    OsQuit,
27}
28
29impl fmt::Display for SignalKind {
30    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31        f.write_str(match self {
32            SignalKind::Cancel => "Cancellation token or channel",
33            SignalKind::OsInt => "SIGINT",
34            SignalKind::OsTerm => "SIGTERM",
35            SignalKind::OsQuit => "SIGQUIT",
36        })
37    }
38}
39
40pub(crate) enum StopSignal {
41    /// OS signal handling is configured.
42    Os(OsSignals),
43
44    /// Cancellation token or channel.
45    Cancel(BoxFuture<'static, ()>),
46}
47
48impl Future for StopSignal {
49    type Output = SignalKind;
50
51    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
52        match self.get_mut() {
53            StopSignal::Os(os_signals) => pin!(os_signals).poll(cx),
54            StopSignal::Cancel(cancel) => pin!(cancel).poll(cx).map(|()| SignalKind::Cancel),
55        }
56    }
57}
58
59/// Process signal listener.
60pub(crate) struct OsSignals {
61    #[cfg(not(unix))]
62    signals: futures_core::future::BoxFuture<'static, std::io::Result<()>>,
63
64    #[cfg(unix)]
65    signals: Vec<(SignalKind, actix_rt::signal::unix::Signal)>,
66}
67
68impl OsSignals {
69    /// Constructs an OS signal listening future.
70    pub(crate) fn new() -> Self {
71        trace!("setting up OS signal listener");
72
73        #[cfg(not(unix))]
74        {
75            OsSignals {
76                signals: Box::pin(actix_rt::signal::ctrl_c()),
77            }
78        }
79
80        #[cfg(unix)]
81        {
82            use actix_rt::signal::unix;
83
84            let sig_map = [
85                (unix::SignalKind::interrupt(), SignalKind::OsInt),
86                (unix::SignalKind::terminate(), SignalKind::OsTerm),
87                (unix::SignalKind::quit(), SignalKind::OsQuit),
88            ];
89
90            let signals = sig_map
91                .iter()
92                .filter_map(|(kind, sig)| {
93                    unix::signal(*kind)
94                        .map(|tokio_sig| (*sig, tokio_sig))
95                        .map_err(|e| {
96                            tracing::error!(
97                                "can not initialize stream handler for {:?} err: {}",
98                                sig,
99                                e
100                            )
101                        })
102                        .ok()
103                })
104                .collect::<Vec<_>>();
105
106            OsSignals { signals }
107        }
108    }
109}
110
111impl Future for OsSignals {
112    type Output = SignalKind;
113
114    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
115        #[cfg(not(unix))]
116        {
117            self.signals.as_mut().poll(cx).map(|_| SignalKind::OsInt)
118        }
119
120        #[cfg(unix)]
121        {
122            for (sig, fut) in self.signals.iter_mut() {
123                if fut.poll_recv(cx).is_ready() {
124                    trace!("{} received", sig);
125                    return Poll::Ready(*sig);
126                }
127            }
128
129            Poll::Pending
130        }
131    }
132}
133
134#[cfg(test)]
135mod tests {
136    use super::*;
137
138    static_assertions::assert_impl_all!(StopSignal: Send, Unpin);
139}