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#[derive(Debug, Clone, Copy, PartialEq)]
14#[allow(dead_code)] pub(crate) enum SignalKind {
16 Cancel,
18
19 OsInt,
21
22 OsTerm,
24
25 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(OsSignals),
43
44 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
59pub(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 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}