signal: move into tokio-net (#1463)

This commit is contained in:
Carl Lerche
2019-08-17 13:43:55 -07:00
committed by Ivan Petkov
parent a83f5e4ba6
commit c187cd75b6
28 changed files with 109 additions and 383 deletions
-1
View File
@@ -10,7 +10,6 @@ members = [
"tokio-macros",
"tokio-net",
"tokio-process",
"tokio-signal",
"tokio-sync",
"tokio-test",
"tokio-timer",
+1 -1
View File
@@ -48,11 +48,11 @@ jobs:
crates:
tokio-fs: []
tokio-net:
- signal
- tcp
- udp
- uds
tokio-process: []
tokio-signal: []
# Test crates that are NOT platform specific
- template: ci/azure-test-stable.yml
-1
View File
@@ -9,7 +9,6 @@ tokio-fs = { path = "tokio-fs" }
tokio-io = { path = "tokio-io" }
tokio-macros = { path = "tokio-macros" }
tokio-net = { path = "tokio-net" }
tokio-signal = { path = "tokio-signal" }
tokio-sync = { path = "tokio-sync" }
tokio-timer = { path = "tokio-timer" }
tokio-tls = { path = "tokio-tls" }
+14 -1
View File
@@ -22,6 +22,13 @@ categories = ["asynchronous", "network-programming"]
[features]
async-traits = []
signal = [
"futures-util-preview",
"mio-uds",
"libc",
"signal-hook-registry",
"winapi",
]
tcp = [
"bytes",
"futures-util-preview",
@@ -62,10 +69,16 @@ futures-sink-preview = { version = "=0.3.0-alpha.18", optional = true }
futures-util-preview = { version = "=0.3.0-alpha.18", optional = true }
iovec = { version = "0.1", optional = true }
# UDS
[target.'cfg(unix)'.dependencies]
# UDS / Signal
mio-uds = { version = "0.6.5", optional = true }
libc = { version = "0.2.42", optional = true }
signal-hook-registry = { version = "~1", optional = true }
[target.'cfg(windows)'.dependencies.winapi]
version = "0.3"
features = ["consoleapi", "minwindef", "wincon"]
optional = true
[dev-dependencies]
tokio = { version = "=0.2.0-alpha.1", path = "../tokio" }
+3
View File
@@ -40,6 +40,9 @@
pub mod driver;
pub mod util;
#[cfg(feature = "signal")]
pub mod signal;
#[cfg(feature = "tcp")]
pub mod tcp;
@@ -1,9 +1,8 @@
#[cfg(unix)]
use crate::unix::Signal as Inner;
use super::unix::Signal as Inner;
#[cfg(windows)]
use crate::windows::Event as Inner;
use tokio_net::driver::Handle;
use super::windows::Event as Inner;
use crate::driver::Handle;
use futures_core::stream::Stream;
use std::io;
@@ -1,13 +1,3 @@
#![doc(html_root_url = "https://docs.rs/tokio-signal/0.3.0-alpha.1")]
#![warn(
missing_debug_implementations,
missing_docs,
rust_2018_idioms,
unreachable_pub
)]
#![cfg_attr(test, feature(async_await))]
#![doc(test(no_crate_inject, attr(deny(rust_2018_idioms))))]
//! Asynchronous signal handling for Tokio
//!
//! This crate implements asynchronous signal handling for Tokio, an
@@ -30,6 +20,8 @@
//! ```rust,no_run
//! #![feature(async_await)]
//!
//! use tokio_net::signal;
//!
//! use futures_util::future;
//! use futures_util::stream::StreamExt;
//!
@@ -37,7 +29,7 @@
//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
//! // Create an infinite stream of "Ctrl+C" notifications. Each item received
//! // on this stream may represent multiple ctrl-c signals.
//! let ctrl_c = tokio_signal::CtrlC::new()?;
//! let ctrl_c = signal::CtrlC::new()?;
//!
//! // Process each ctrl-c as it comes in
//! let prog = ctrl_c.for_each(|_| {
@@ -57,15 +49,16 @@
//! #![feature(async_await)]
//! # #[cfg(unix)] {
//!
//! use tokio_net::signal::{self, unix::{Signal, SignalKind}};
//!
//! use futures_util::future;
//! use futures_util::stream::StreamExt;
//! use tokio_signal::unix::{Signal, SignalKind};
//!
//! #[tokio::main]
//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
//! // Create an infinite stream of "Ctrl+C" notifications. Each item received
//! // on this stream may represent multiple ctrl-c signals.
//! let ctrl_c = tokio_signal::CtrlC::new()?;
//! let ctrl_c = signal::CtrlC::new()?;
//!
//! // Process each ctrl-c as it comes in
//! let prog = ctrl_c.for_each(|_| {
@@ -87,9 +80,6 @@
//! # }
//! ```
#[macro_use]
extern crate lazy_static;
mod ctrl_c;
mod registry;
@@ -103,4 +93,4 @@ mod os {
pub mod unix;
pub mod windows;
pub use ctrl_c::CtrlC;
pub use self::ctrl_c::CtrlC;
@@ -1,11 +1,13 @@
use super::os::{OsExtraData, OsStorage};
use tokio_sync::mpsc::Sender;
use lazy_static::lazy_static;
use std::ops;
use std::pin::Pin;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Mutex;
use crate::os::{OsExtraData, OsStorage};
use tokio_sync::mpsc::Sender;
pub(crate) type EventId = usize;
/// State for a specific event, whether a notification is pending delivery,
@@ -5,13 +5,15 @@
#![cfg(unix)]
pub use libc;
use super::registry::{globals, EventId, EventInfo, Globals, Init, Storage};
use crate::driver::Handle;
use crate::util::PollEvented;
use tokio_io::AsyncRead;
use tokio_net::driver::Handle;
use tokio_net::util::PollEvented;
use tokio_sync::mpsc::{channel, Receiver};
pub use libc;
use futures_core::stream::Stream;
use libc::c_int;
use mio_uds::UnixStream;
@@ -22,8 +24,6 @@ use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Once;
use std::task::{Context, Poll};
use crate::registry::{globals, EventId, EventInfo, Globals, Init, Storage};
pub(crate) type OsStorage = Vec<SignalInfo>;
// Number of different unix signals
@@ -73,7 +73,7 @@ impl SignalKind {
/// For example, this can be used for listening for platform-specific
/// signals.
/// ```rust,no_run
/// # use tokio_signal::unix::SignalKind;
/// # use tokio_net::signal::unix::SignalKind;
/// # let signum = -1;
/// // let signum = libc::OS_SPECIFIC_SIGNAL;
/// let kind = SignalKind::from_raw(signum);
@@ -438,11 +438,6 @@ impl Stream for Signal {
#[cfg(test)]
mod tests {
use super::*;
use futures_util::future::FutureExt;
use futures_util::StreamExt;
use std::time::Duration;
use tokio_sync::oneshot;
use tokio_timer::Timeout;
#[test]
fn signal_enable_error_on_invalid_input() {
@@ -453,25 +448,4 @@ mod tests {
fn signal_enable_error_on_forbidden_input() {
signal_enable(signal_hook_registry::FORBIDDEN[0]).unwrap_err();
}
fn with_timeout<F: Future>(future: F) -> impl Future<Output = F::Output> {
Timeout::new(future, Duration::from_secs(1)).map(|result| result.expect("timed out"))
}
#[tokio::test]
async fn ctrl_c() {
let ctrl_c = crate::CtrlC::new().expect("failed to init ctrl_c");
let (fire, wait) = oneshot::channel();
// NB: simulate a signal coming in by exercising our signal handler
// to avoid complications with sending SIGINT to the test process
tokio::spawn(async {
wait.await.expect("wait failed");
action(globals(), libc::SIGINT);
});
let _ = fire.send(());
let _ = with_timeout(ctrl_c.into_future()).await;
}
}
@@ -7,9 +7,9 @@
#![cfg(windows)]
use crate::registry::{globals, EventId, EventInfo, Init, Storage};
use super::registry::{globals, EventId, EventInfo, Init, Storage};
use crate::driver::Handle;
use tokio_net::driver::Handle;
use tokio_sync::mpsc::{channel, Receiver};
use futures_core::stream::Stream;
@@ -198,11 +198,13 @@ impl Stream for CtrlBreak {
#[cfg(test)]
mod tests {
use super::*;
use tokio::timer::Timeout;
use futures_util::future::FutureExt;
use futures_util::stream::StreamExt;
use std::future::Future;
use std::time::Duration;
use tokio_timer::Timeout;
fn with_timeout<F: Future>(future: F) -> impl Future<Output = F::Output> {
Timeout::new(future, Duration::from_secs(1)).map(|result| result.expect("timed out"))
@@ -210,7 +212,7 @@ mod tests {
#[tokio::test]
async fn ctrl_c() {
let ctrl_c = crate::CtrlC::new().expect("failed to create CtrlC");
let ctrl_c = crate::signal::CtrlC::new().expect("failed to create CtrlC");
// Windows doesn't have a good programmatic way of sending events
// like sending signals on Unix, so we'll stub out the actual OS
@@ -1,10 +1,9 @@
#![cfg(unix)]
#![cfg(feature = "signal")]
#![warn(rust_2018_idioms)]
use libc;
pub mod support;
use crate::support::*;
pub mod signal_support;
use crate::signal_support::*;
#[test]
fn dropping_loops_does_not_cause_starvation() {
@@ -1,11 +1,10 @@
#![cfg(unix)]
#![cfg(feature = "signal")]
#![warn(rust_2018_idioms)]
#![feature(async_await)]
use libc;
pub mod support;
use crate::support::*;
pub mod signal_support;
use crate::signal_support::*;
#[tokio::test]
async fn drop_then_get_a_signal() {
@@ -1,11 +1,10 @@
#![cfg(unix)]
#![cfg(feature = "signal")]
#![warn(rust_2018_idioms)]
#![feature(async_await)]
use libc;
pub mod support;
use crate::support::*;
pub mod signal_support;
use crate::signal_support::*;
#[tokio::test]
async fn dropping_signal_does_not_deregister_any_other_instances() {
@@ -1,10 +1,10 @@
#![cfg(unix)]
#![cfg(feature = "signal")]
#![warn(rust_2018_idioms)]
pub mod support;
use crate::support::*;
pub mod signal_support;
use crate::signal_support::*;
use libc;
use std::sync::mpsc::channel;
use std::thread;
@@ -1,11 +1,10 @@
#![cfg(unix)]
#![cfg(feature = "signal")]
#![warn(rust_2018_idioms)]
#![feature(async_await)]
pub mod support;
use crate::support::*;
use libc;
pub mod signal_support;
use crate::signal_support::*;
#[tokio::test]
async fn notify_both() {
+37
View File
@@ -0,0 +1,37 @@
#![cfg(unix)]
#![cfg(feature = "signal")]
#![warn(rust_2018_idioms)]
#![feature(async_await)]
pub mod signal_support;
use crate::signal_support::*;
#[tokio::test]
async fn simple() {
let signal = Signal::new(SignalKind::user_defined1()).expect("failed to create signal");
send_signal(libc::SIGUSR1);
let _ = with_timeout(signal.into_future()).await;
}
#[tokio::test]
#[cfg(unix)]
async fn ctrl_c() {
use tokio::sync::oneshot;
use tokio_net::signal::CtrlC;
let ctrl_c = CtrlC::new().expect("failed to init ctrl_c");
let (fire, wait) = oneshot::channel();
// NB: simulate a signal coming in by exercising our signal handler
// to avoid complications with sending SIGINT to the test process
tokio::spawn(async {
wait.await.expect("wait failed");
send_signal(libc::SIGINT);
});
let _ = fire.send(());
let _ = with_timeout(ctrl_c.into_future()).await;
}
@@ -1,16 +1,16 @@
#![cfg(unix)]
#![warn(rust_2018_idioms)]
pub use tokio::runtime::current_thread::{self, Runtime as CurrentThreadRuntime};
use tokio::timer::Timeout;
pub use tokio_net::signal::unix::{Signal, SignalKind};
pub use futures_util::future;
use futures_util::future::FutureExt;
pub use futures_util::stream::StreamExt;
use libc::{c_int, getpid, kill};
use std::future::Future;
use std::time::Duration;
use tokio_timer::Timeout;
pub use futures_util::future;
pub use futures_util::stream::StreamExt;
pub use tokio::runtime::current_thread::{self, Runtime as CurrentThreadRuntime};
pub use tokio_signal::unix::{Signal, SignalKind};
pub fn with_timeout<F: Future>(future: F) -> impl Future<Output = F::Output> {
Timeout::new(future, Duration::from_secs(1)).map(Result::unwrap)
@@ -1,11 +1,10 @@
#![cfg(unix)]
#![cfg(feature = "signal")]
#![warn(rust_2018_idioms)]
#![feature(async_await)]
pub mod support;
use crate::support::*;
use libc;
pub mod signal_support;
use crate::signal_support::*;
#[tokio::test]
async fn twice() {
+1 -1
View File
@@ -55,4 +55,4 @@ lazy_static = "1.3"
libc = "0.2"
log = "0.4"
mio = "0.6.5"
tokio-signal = { version = "=0.3.0-alpha.1", path = "../tokio-signal" }
tokio-net = { version = "=0.2.0-alpha.1", path = "../tokio-net", features = ["signal"] }
+2 -2
View File
@@ -11,7 +11,7 @@
//!
//! Our best approximation here is to check *all spawned processes* for all
//! SIGCHLD signals received. To do that we create a `Signal`, implemented in
//! the `tokio-signal` crate, which is a stream over signals being received.
//! the `tokio-net` crate, which is a stream over signals being received.
//!
//! Later when we poll the process's exit status we simply check to see if a
//! SIGCHLD has happened since we last checked, and while that returns "yes" we
@@ -30,8 +30,8 @@ use super::SpawnedChild;
use crate::kill::Kill;
use tokio_net::driver::Handle;
use tokio_net::signal::unix::{Signal, SignalKind};
use tokio_net::util::PollEvented;
use tokio_signal::unix::{Signal, SignalKind};
use mio::event::Evented;
use mio::unix::{EventedFd, UnixReady};
-63
View File
@@ -1,63 +0,0 @@
# 0.3.0-alpha.1 (August 8, 2019)
### Changed
- Switch to `async`, `await`, and `std::future`.
- `windows::Event` has been removed in favor of `CtrlC` and
a separate `windows::CtrlBreak` struct.
- `ctrl_c{,_with_handle}` has been replaced with a `CtrlC` struct
(which can be constructed via `CtrlC::{new, with_handle}`.
- `unix::Signal` returns `()` instead of the signal number used in registration
- `unis::Signal` constructors now return a simple result rather than a lazy future
# 0.2.9
### Fixed
- `windows::Event` performs internal registrations lazily, so now it can be
constructed outside of a running task
- remove usage of deprecated `Handle::current` in default `windows::Event`
constructors
# 0.2.8 (March 22, 2019)
### Fixed
- remove usage of deprecated `Handle::current` (#981).
## 0.2.7 - (November 21, 2018)
### Changed
* `unix::Signal` now implements `Sync`
* minimize allocations
### Fixes
* `unix::Signal` now avoids extraneous wakeups generated as a result of
dropping other instances
## 0.2.6 - (October 26, 2018)
### Changed
* Use the `signal-hook` crate for managing signal registrations
## 0.2.5 - (September 29, 2018)
### Fixes
* Fix a possible starvation when polling multiple `Signal` instances outside of
a tokio reactor (e.g. by using `Future::wait`)
## 0.2.4 - (August 25, 2018)
### Fixes
* Actually make `unix::bsd` public
## 0.2.3 - (August 25, 2018)
### Features
* Exposes `SIGINFO` on BSD-based operating systems.
## 0.2.2 - (August 14, 2018)
### Fixes
* Fix starvation of `Signal`s whenever a `Signal` instance is dropped
* Fix starvation of individual `Signal`s based on their creation order
## 0.2.1 - (May 27, 2018)
### Fixes
* Bump minimum supported version of `mio` to 0.6.14
## 0.2.0 - (May 7, 2018)
#### Features
* Uses `tokio` instead of `tokio_core`
* Supports all 33 signals on FreeBSD
-43
View File
@@ -1,43 +0,0 @@
[package]
name = "tokio-signal"
# When releasing to crates.io:
# - Remove path dependencies
# - Update html_root_url.
# - Update doc url
# - Cargo.toml
# - Update CHANGELOG.md.
# - Create "v0.3.x" git tag.
version = "0.3.0-alpha.1"
edition = "2018"
authors = ["Tokio Contributors <[email protected]>"]
license = "MIT"
repository = "https://github.com/tokio-rs/tokio"
homepage = "https://github.com/tokio-rs/tokio"
documentation = "https://docs.rs/tokio-signal/0.3.0-alpha.1/tokio_signal"
description = """
An implementation of an asynchronous Unix signal handling backed futures.
"""
categories = ["asynchronous"]
[dependencies]
futures-core-preview = "=0.3.0-alpha.18"
futures-util-preview = "=0.3.0-alpha.18"
lazy_static = "1"
tokio-io = { version = "=0.2.0-alpha.1", path = "../tokio-io" }
tokio-net = { version = "=0.2.0-alpha.1", path = "../tokio-net" }
tokio-sync = { version = "=0.2.0-alpha.1", path = "../tokio-sync" }
[target.'cfg(unix)'.dependencies]
libc = "0.2"
mio = "0.6.14"
mio-uds = "0.6"
signal-hook-registry = "~1"
[dev-dependencies]
tokio = { version = "=0.2.0-alpha.1", path = "../tokio" }
tokio-timer = { version = "=0.3.0-alpha.1", path = "../tokio-timer" }
tokio-sync = { version = "=0.2.0-alpha.1", path = "../tokio-sync", features = ["async-traits"]}
[target.'cfg(windows)'.dependencies.winapi]
version = "0.3"
features = ["consoleapi", "minwindef", "wincon"]
-25
View File
@@ -1,25 +0,0 @@
Copyright (c) 2019 Tokio contributors
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without
limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions
of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
-13
View File
@@ -1,13 +0,0 @@
# tokio-signal
Unix signal handling for Tokio.
## License
This project is licensed under the [MIT license](./LICENSE).
### Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in Tokio by you, shall be licensed as MIT, without any additional
terms or conditions.
-42
View File
@@ -1,42 +0,0 @@
#![warn(rust_2018_idioms)]
#![feature(async_await)]
use futures_util::stream::StreamExt;
/// how many signals to handle before exiting
const STOP_AFTER: u64 = 10;
#[tokio::main]
async fn main() {
// tokio_signal provides a convenience builder for Ctrl+C
// this even works cross-platform: linux and windows!
let endless_stream = tokio_signal::CtrlC::new().expect("failed to create CtrlC");
// don't keep going forever: convert the endless stream to a bounded one.
let mut limited_stream = endless_stream.take(STOP_AFTER);
// how many Ctrl+C have we received so far?
let mut counter = 0;
println!(
"This program is now waiting for you to press Ctrl+C {0} times. \
Terminate by repeating Ctrl+C {0} times, or ahead of time by opening \
a second terminal and issuing `pkill -sigkil ctrl-c`.",
STOP_AFTER
);
// Up until now, we haven't really DONE anything, just prepared
// our futures, now it's time to actually await the results!
while let Some(_) = limited_stream.next().await {
// Note how we manipulate the counter without any fancy synchronisation.
// The borrowchecker realises there can't be any conflicts, so the closure
// can just capture it.
counter += 1;
println!(
"Ctrl+C received {} times! {} more before exit",
counter,
STOP_AFTER - counter
);
}
println!("Stream ended, quiting the program.");
}
-47
View File
@@ -1,47 +0,0 @@
#![warn(rust_2018_idioms)]
#![feature(async_await)]
//! A small example of how to listen for two signals at the same time
// A trick to not fail build on non-unix platforms when using unix-specific features.
#[cfg(unix)]
mod platform {
use futures_util::stream::{self, StreamExt};
use tokio_signal::unix::{Signal, SignalKind};
pub async fn main() {
// Create a stream for each of the signals we'd like to handle.
let sigint = Signal::new(SignalKind::interrupt())
.unwrap()
.map(|_| "SIGINT");
let sigterm = Signal::new(SignalKind::terminate())
.unwrap()
.map(|_| "SIGTERM");
// Use the `select` combinator to merge these two streams into one
let stream = stream::select(sigint, sigterm);
// Wait for a signal to arrive
println!("Waiting for SIGINT or SIGTERM");
println!(
" TIP: use `pkill -sigint multiple` from a second terminal \
to send a SIGINT to all processes named 'multiple' \
(i.e. this binary)"
);
let (item, _rest) = stream.into_future().await;
// Figure out which signal we received
let msg = item.ok_or("received no signal").unwrap();
println!("received {}", msg);
}
}
#[cfg(not(unix))]
mod platform {
pub async fn main() {}
}
#[tokio::main]
async fn main() {
platform::main().await
}
-37
View File
@@ -1,37 +0,0 @@
#![warn(rust_2018_idioms)]
#![feature(async_await)]
// A trick to not fail build on non-unix platforms when using unix-specific features.
#[cfg(unix)]
mod platform {
use futures_util::stream::StreamExt;
use tokio_signal::unix::{Signal, SignalKind};
pub async fn main() {
// on Unix, we can listen to whatever signal we want, in this case: SIGHUP
let mut stream = Signal::new(SignalKind::hangup()).unwrap();
println!("Waiting for SIGHUPS (Ctrl+C to quit)");
println!(
" TIP: use `pkill -sighup sighup-example` from a second terminal \
to send a SIGHUP to all processes named 'sighup-example' \
(i.e. this binary)"
);
// Up until now, we haven't really DONE anything, just prepared
// our futures, now it's time to actually await the results!
while let Some(_) = stream.next().await {
println!("*Got signal* I should probably reload my config or something");
}
}
}
#[cfg(not(unix))]
mod platform {
pub async fn main() {}
}
#[tokio::main]
async fn main() {
platform::main().await
}
-17
View File
@@ -1,17 +0,0 @@
#![cfg(unix)]
#![warn(rust_2018_idioms)]
#![feature(async_await)]
pub mod support;
use crate::support::*;
use libc;
#[tokio::test]
async fn simple() {
let signal = Signal::new(SignalKind::user_defined1()).expect("failed to create signal");
send_signal(libc::SIGUSR1);
let _ = with_timeout(signal.into_future()).await;
}