#
actix_server/
signals.rs

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108

    use std::{
        fmt,
        future::Future,
        pin::Pin,
        task::{Context, Poll},
    };

    use tracing::trace;

    /// Types of process signals.
    // #[allow(dead_code)]
    #[derive(Debug, Clone, Copy, PartialEq)]
    #[allow(dead_code)] // variants are never constructed on non-unix
    pub(crate) enum SignalKind {
        /// `SIGINT`
        Int,

        /// `SIGTERM`
        Term,

        /// `SIGQUIT`
        Quit,
    }

    impl fmt::Display for SignalKind {
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            f.write_str(match self {
                SignalKind::Int => "SIGINT",
                SignalKind::Term => "SIGTERM",
                SignalKind::Quit => "SIGQUIT",
            })
        }
    }

    /// Process signal listener.
    pub(crate) struct Signals {
        #[cfg(not(unix))]
        signals: futures_core::future::BoxFuture<'static, std::io::Result<()>>,

        #[cfg(unix)]
        signals: Vec<(SignalKind, actix_rt::signal::unix::Signal)>,
    }

    impl Signals {
        /// Constructs an OS signal listening future.
        pub(crate) fn new() -> Self {
            trace!("setting up OS signal listener");

            #[cfg(not(unix))]
            {
                Signals {
                    signals: Box::pin(actix_rt::signal::ctrl_c()),
                }
            }

            #[cfg(unix)]
            {
                use actix_rt::signal::unix;

                let sig_map = [
                    (unix::SignalKind::interrupt(), SignalKind::Int),
                    (unix::SignalKind::terminate(), SignalKind::Term),
                    (unix::SignalKind::quit(), SignalKind::Quit),
                ];

                let signals = sig_map
                    .iter()
                    .filter_map(|(kind, sig)| {
                        unix::signal(*kind)
                            .map(|tokio_sig| (*sig, tokio_sig))
                            .map_err(|e| {
                                tracing::error!(
                                    "can not initialize stream handler for {:?} err: {}",
                                    sig,
                                    e
                                )
                            })
                            .ok()
                    })
                    .collect::<Vec<_>>();

                Signals { signals }
            }
        }
    }

    impl Future for Signals {
        type Output = SignalKind;

        fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
            #[cfg(not(unix))]
            {
                self.signals.as_mut().poll(cx).map(|_| SignalKind::Int)
            }

            #[cfg(unix)]
            {
                for (sig, fut) in self.signals.iter_mut() {
                    if fut.poll_recv(cx).is_ready() {
                        trace!("{} received", sig);
                        return Poll::Ready(*sig);
                    }
                }

                Poll::Pending
            }
        }
    }