~zethra/stargazer

01b4ca66aa08d75cbfb7bda0d012882fe3f547ed — Ben Aaron Goldberg 28 days ago d5c9c9d
deps+signals: Upgrade signal_hook to 0.3 + add signal module

signal_hook 0.3 changed the API a fair bit. They broke async support out
into other crates non of which support smol. So for now I've pulled a
smol port of signal_hook_async_std in tree as the signal module. I've
also sent the changes to signal_hook_async_std upstream as they're still
compatible with async-std. If they're accepted by upstream I'll switch
to using signal_hook_async_std.
4 files changed, 123 insertions(+), 12 deletions(-)

M Cargo.lock
M Cargo.toml
M src/main.rs
A src/signal.rs
M Cargo.lock => Cargo.lock +12 -2
@@ 131,7 131,7 @@ dependencies = [
 "event-listener",
 "futures-lite",
 "once_cell",
 "signal-hook",
 "signal-hook 0.1.17",
 "winapi",
]



@@ 983,6 983,16 @@ dependencies = [
]

[[package]]
name = "signal-hook"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "780f5e3fe0c66f67197236097d89de1e86216f1f6fdeaf47c442f854ab46c240"
dependencies = [
 "libc",
 "signal-hook-registry",
]

[[package]]
name = "signal-hook-registry"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 1028,7 1038,7 @@ dependencies = [
 "regex",
 "rust-ini",
 "sha2",
 "signal-hook",
 "signal-hook 0.3.4",
 "structopt",
 "uriparse",
 "users",

M Cargo.toml => Cargo.toml +1 -1
@@ 48,7 48,7 @@ structopt = "0.3"
rcgen = "0.8"
dirs = "3.0"
rust-ini = "0.16"
signal-hook = "0.1"
signal-hook = "0.3"
regex = "1.4"
x509-parser = "0.9"
sha2 = "0.9"

M src/main.rs => src/main.rs +8 -9
@@ 22,9 22,11 @@ mod error;
mod get_file;
mod logger;
mod router;
#[cfg(unix)]
mod signal;
mod tls;

use crate::error::{bad_req, GemError, Result, ErrorConv};
use crate::error::{bad_req, ErrorConv, GemError, Result};
use async_channel::{Receiver, Sender};
use async_executor::Executor;
use async_io::Timer;


@@ 202,14 204,11 @@ fn main() {

#[cfg(unix)]
async fn exit_on_sig() -> Result<()> {
    let (sigint_a, mut sigint_b) = async_net::unix::UnixStream::pair()?;
    signal_hook::pipe::register(signal_hook::SIGINT, sigint_a)?;
    let (sigterm_a, mut sigterm_b) = async_net::unix::UnixStream::pair()?;
    signal_hook::pipe::register(signal_hook::SIGTERM, sigterm_a)?;
    sigint_b
        .read_exact(&mut [0])
        .or(sigterm_b.read_exact(&mut [0]))
        .await?;
    use crate::signal::Signals;
    use signal_hook::consts::{SIGINT, SIGTERM};

    let mut signals = Signals::new(&[SIGTERM, SIGINT])?;
    signals.next().await;
    SHUTDOWN.0.send(()).await?;
    log::logger().flush();
    std::process::exit(0);

A src/signal.rs => src/signal.rs +102 -0
@@ 0,0 1,102 @@
#![allow(dead_code)]

//! A smol port of signal_hook_async_std

use std::borrow::Borrow;
use std::io::Error;
use std::os::unix::net::UnixStream;
use std::pin::Pin;
use std::task::{Context, Poll};

use libc::c_int;

pub use signal_hook::iterator::backend::Handle;
use signal_hook::iterator::backend::{
    OwningSignalIterator, PollResult, SignalDelivery,
};
use signal_hook::iterator::exfiltrator::{Exfiltrator, SignalOnly};

use async_io::Async;
use futures_lite::io::AsyncRead;
use futures_lite::Stream;

/// An asynchronous [`Stream`] of arriving signals.
///
/// The stream doesn't return the signals in the order they were recieved by
/// the process and may merge signals received multiple times.
pub struct SignalsInfo<E: Exfiltrator = SignalOnly>(
    OwningSignalIterator<Async<UnixStream>, E>,
);

impl<E: Exfiltrator> SignalsInfo<E> {
    /// Create a `Signals` instance.
    ///
    /// This registers all the signals listed. The same restrictions (panics, errors) apply
    /// as with [`Handle::add_signal`].
    pub fn new<I, S>(signals: I) -> Result<Self, Error>
    where
        I: IntoIterator<Item = S>,
        S: Borrow<c_int>,
        E: Default,
    {
        Self::with_exfiltrator(signals, E::default())
    }

    /// A constructor with explicit exfiltrator.
    pub fn with_exfiltrator<I, S>(
        signals: I,
        exfiltrator: E,
    ) -> Result<Self, Error>
    where
        I: IntoIterator<Item = S>,
        S: Borrow<c_int>,
    {
        let (read, write) = Async::<UnixStream>::pair()?;
        let inner =
            SignalDelivery::with_pipe(read, write, exfiltrator, signals)?;
        Ok(Self(OwningSignalIterator::new(inner)))
    }

    /// Get a shareable [`Handle`] for this `Signals` instance.
    ///
    /// This can be used to add further signals or close the [`Signals`] instance
    /// which terminates the whole signal stream.
    pub fn handle(&self) -> Handle {
        self.0.handle()
    }
}

impl SignalsInfo {
    fn has_signals(
        read: &mut Async<UnixStream>,
        ctx: &mut Context<'_>,
    ) -> Result<bool, Error> {
        match Pin::new(read).poll_read(ctx, &mut [0u8]) {
            Poll::Pending => Ok(false),
            Poll::Ready(Ok(num_read)) => Ok(num_read > 0),
            Poll::Ready(Err(error)) => Err(error),
        }
    }
}

impl Stream for SignalsInfo {
    type Item = c_int;

    fn poll_next(
        mut self: Pin<&mut Self>,
        ctx: &mut Context<'_>,
    ) -> Poll<Option<Self::Item>> {
        match self.0.poll_signal(&mut |read| Self::has_signals(read, ctx)) {
            PollResult::Signal(sig) => Poll::Ready(Some(sig)),
            PollResult::Closed => Poll::Ready(None),
            PollResult::Pending => Poll::Pending,
            PollResult::Err(error) => panic!("Unexpected error: {}", error),
        }
    }
}

/// Simplified version of the signals stream.
///
/// This one simply returns the signal numbers, while [`SignalsInfo`] can provide additional
/// information.
pub type Signals = SignalsInfo<SignalOnly>;