summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIvan Petkov <ivanppetkov@gmail.com>2019-08-13 21:07:22 -0700
committerCarl Lerche <me@carllerche.com>2019-08-13 21:07:22 -0700
commit338b37884a73782fe72d4e9a0616010bcd12180e (patch)
treea56fde0234b07cd418cc6da3b54770435302561b
parent513326e01da05261fbb05f722836c7cb80552773 (diff)
signal: Add SignalKind for registering signals more easily (#1430)
This avoids having consumers import libc for common signals, and it improves discoverability since users need not be aware that libc contains all supported constants.
-rw-r--r--tokio-process/src/unix/mod.rs4
-rw-r--r--tokio-signal/examples/multiple.rs17
-rw-r--r--tokio-signal/examples/sighup-example.rs4
-rw-r--r--tokio-signal/src/lib.rs4
-rw-r--r--tokio-signal/src/unix.rs166
-rw-r--r--tokio-signal/tests/drop_multi_loop.rs12
-rw-r--r--tokio-signal/tests/drop_then_get_a_signal.rs5
-rw-r--r--tokio-signal/tests/dropping_does_not_deregister_other_instances.rs12
-rw-r--r--tokio-signal/tests/multi_loop.rs2
-rw-r--r--tokio-signal/tests/notify_both.rs5
-rw-r--r--tokio-signal/tests/simple.rs2
-rw-r--r--tokio-signal/tests/support.rs2
-rw-r--r--tokio-signal/tests/twice.rs3
13 files changed, 169 insertions, 69 deletions
diff --git a/tokio-process/src/unix/mod.rs b/tokio-process/src/unix/mod.rs
index 55497cad..f6d6b67a 100644
--- a/tokio-process/src/unix/mod.rs
+++ b/tokio-process/src/unix/mod.rs
@@ -40,7 +40,7 @@ use std::process::{self, ExitStatus};
use std::task::Context;
use std::task::Poll;
use tokio_reactor::{Handle, PollEvented};
-use tokio_signal::unix::Signal;
+use tokio_signal::unix::{Signal, SignalKind};
impl Wait for process::Child {
fn id(&self) -> u32 {
@@ -99,7 +99,7 @@ pub(crate) fn spawn_child(cmd: &mut process::Command, handle: &Handle) -> io::Re
let stdout = stdio(child.stdout.take(), handle)?;
let stderr = stdio(child.stderr.take(), handle)?;
- let signal = Signal::with_handle(libc::SIGCHLD, handle)?;
+ let signal = Signal::with_handle(SignalKind::sigchld(), handle)?;
Ok(SpawnedChild {
child: Child {
diff --git a/tokio-signal/examples/multiple.rs b/tokio-signal/examples/multiple.rs
index 5157fb1b..7732d221 100644
--- a/tokio-signal/examples/multiple.rs
+++ b/tokio-signal/examples/multiple.rs
@@ -7,12 +7,14 @@
#[cfg(unix)]
mod platform {
use futures_util::stream::{self, StreamExt};
- use tokio_signal::unix::{Signal, SIGINT, SIGTERM};
+ 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(SIGINT).unwrap().map(|_| SIGINT);
- let sigterm = Signal::new(SIGTERM).unwrap().map(|_| SIGTERM);
+ let sigint = Signal::new(SignalKind::sigint()).unwrap().map(|_| "SIGINT");
+ let sigterm = Signal::new(SignalKind::sigterm())
+ .unwrap()
+ .map(|_| "SIGTERM");
// Use the `select` combinator to merge these two streams into one
let stream = stream::select(sigint, sigterm);
@@ -27,13 +29,8 @@ mod platform {
let (item, _rest) = stream.into_future().await;
// Figure out which signal we received
- let item = item.ok_or("received no signal").unwrap();
- if item == SIGINT {
- println!("received SIGINT");
- } else {
- assert_eq!(item, SIGTERM);
- println!("received SIGTERM");
- }
+ let msg = item.ok_or("received no signal").unwrap();
+ println!("received {}", msg);
}
}
diff --git a/tokio-signal/examples/sighup-example.rs b/tokio-signal/examples/sighup-example.rs
index 6ee46a9d..ed4b04f5 100644
--- a/tokio-signal/examples/sighup-example.rs
+++ b/tokio-signal/examples/sighup-example.rs
@@ -5,11 +5,11 @@
#[cfg(unix)]
mod platform {
use futures_util::stream::StreamExt;
- use tokio_signal::unix::{Signal, SIGHUP};
+ 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(SIGHUP).unwrap();
+ let mut stream = Signal::new(SignalKind::sighup()).unwrap();
println!("Waiting for SIGHUPS (Ctrl+C to quit)");
println!(
diff --git a/tokio-signal/src/lib.rs b/tokio-signal/src/lib.rs
index 36f265cf..c12ed535 100644
--- a/tokio-signal/src/lib.rs
+++ b/tokio-signal/src/lib.rs
@@ -59,7 +59,7 @@
//!
//! use futures_util::future;
//! use futures_util::stream::StreamExt;
-//! use tokio_signal::unix::{Signal, SIGHUP};
+//! use tokio_signal::unix::{Signal, SignalKind};
//!
//! #[tokio::main]
//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
@@ -77,7 +77,7 @@
//!
//! // Like the previous example, this is an infinite stream of signals
//! // being received, and signals may be coalesced while pending.
-//! let stream = Signal::new(SIGHUP)?;
+//! let stream = Signal::new(SignalKind::sighup())?;
//!
//! // Convert out stream into a future and block the program
//! let (signal, _signal) = stream.into_future().await;
diff --git a/tokio-signal/src/unix.rs b/tokio-signal/src/unix.rs
index 65cdc99f..ce7723e0 100644
--- a/tokio-signal/src/unix.rs
+++ b/tokio-signal/src/unix.rs
@@ -23,28 +23,6 @@ use tokio_sync::mpsc::{channel, Receiver};
use crate::registry::{globals, EventId, EventInfo, Globals, Init, Storage};
-pub use libc::{SIGALRM, SIGHUP, SIGPIPE, SIGQUIT, SIGTRAP};
-pub use libc::{SIGINT, SIGTERM, SIGUSR1, SIGUSR2};
-
-/// BSD-specific definitions
-#[cfg(any(
- target_os = "dragonfly",
- target_os = "freebsd",
- target_os = "macos",
- target_os = "netbsd",
- target_os = "openbsd",
-))]
-pub mod bsd {
- #[cfg(any(
- target_os = "dragonfly",
- target_os = "freebsd",
- target_os = "macos",
- target_os = "netbsd",
- target_os = "openbsd"
- ))]
- pub use super::libc::SIGINFO;
-}
-
pub(crate) type OsStorage = Vec<SignalInfo>;
// Number of different unix signals
@@ -84,6 +62,131 @@ impl Init for OsExtraData {
}
}
+/// Represents the specific kind of signal to listen for.
+#[derive(Debug, Clone, Copy)]
+pub struct SignalKind(c_int);
+
+impl SignalKind {
+ /// Allows for listening to any valid OS signal.
+ ///
+ /// For example, this can be used for listening for platform-specific
+ /// signals.
+ /// ```rust,no_run
+ /// # use tokio_signal::unix::SignalKind;
+ /// # let signum = -1;
+ /// // let signum = libc::OS_SPECIFIC_SIGNAL;
+ /// let kind = SignalKind::from_raw(signum);
+ /// ```
+ pub fn from_raw(signum: c_int) -> Self {
+ Self(signum)
+ }
+
+ /// Represents the SIGALRM signal.
+ ///
+ /// On Unix systems this signal is sent when a real-time timer has expired.
+ /// By default, the process is terminated by this signal.
+ pub fn sigalrm() -> Self {
+ Self(libc::SIGALRM)
+ }
+
+ /// Represents the SIGCHLD signal.
+ ///
+ /// On Unix systems this signal is sent when the status of a child process
+ /// has changed. By default, this signal is ignored.
+ pub fn sigchld() -> Self {
+ Self(libc::SIGCHLD)
+ }
+
+ /// Represents the SIGHUP signal.
+ ///
+ /// On Unix systems this signal is sent when the terminal is disconnected.
+ /// By default, the process is terminated by this signal.
+ pub fn sighup() -> Self {
+ Self(libc::SIGHUP)
+ }
+
+ /// Represents the SIGINFO signal.
+ ///
+ /// On Unix systems this signal is sent to request a status update from the
+ /// process. By default, this signal is ignored.
+ #[cfg(any(
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"
+ ))]
+ pub fn siginfo() -> Self {
+ Self(libc::SIGINFO)
+ }
+
+ /// Represents the SIGINT signal.
+ ///
+ /// On Unix systems this signal is sent to interrupt a program.
+ /// By default, the process is terminated by this signal.
+ pub fn sigint() -> Self {
+ Self(libc::SIGINT)
+ }
+
+ /// Represents the SIGIO signal.
+ ///
+ /// On Unix systems this signal is sent when I/O operations are possible
+ /// on some file descriptor. By default, this signal is ignored.
+ pub fn sigio() -> Self {
+ Self(libc::SIGIO)
+ }
+
+ /// Represents the SIGPIPE signal.
+ ///
+ /// On Unix systems this signal is sent when the process attempts to write
+ /// to a pipe which has no reader. By default, the process is terminated by
+ /// this signal.
+ pub fn sigpipe() -> Self {
+ Self(libc::SIGPIPE)
+ }
+
+ /// Represents the SIGQUIT signal.
+ ///
+ /// On Unix systems this signal is sent to issue a shutdown of the
+ /// process, after which the OS will dump the process core.
+ /// By default, the process is terminated by this signal.
+ pub fn sigquit() -> Self {
+ Self(libc::SIGQUIT)
+ }
+
+ /// Represents the SIGTERM signal.
+ ///
+ /// On Unix systems this signal is sent to issue a shutdown of the
+ /// process. By default, the process is terminated by this signal.
+ pub fn sigterm() -> Self {
+ Self(libc::SIGTERM)
+ }
+
+ /// Represents the SIGUSR1 signal.
+ ///
+ /// On Unix systems this is a user defined signal.
+ /// By default, the process is terminated by this signal.
+ pub fn sigusr1() -> Self {
+ Self(libc::SIGUSR1)
+ }
+
+ /// Represents the SIGUSR2 signal.
+ ///
+ /// On Unix systems this is a user defined signal.
+ /// By default, the process is terminated by this signal.
+ pub fn sigusr2() -> Self {
+ Self(libc::SIGUSR2)
+ }
+
+ /// Represents the SIGWINCH signal.
+ ///
+ /// On Unix systems this signal is sent when the terminal window is resized.
+ /// By default, this signal is ignored.
+ pub fn sigwinch() -> Self {
+ Self(libc::SIGWINCH)
+ }
+}
+
pub(crate) struct SignalInfo {
event_info: EventInfo,
init: Once,
@@ -259,10 +362,7 @@ impl Signal {
/// Creates a new stream which will receive notifications when the current
/// process receives the signal `signal`.
///
- /// This function will create a new stream which binds to the default event
- /// loop. This function returns a future which will
- /// then resolve to the signal stream, if successful.
- ///
+ /// This function will create a new stream which binds to the default reactor.
/// The `Signal` stream is an infinite stream which will receive
/// notifications whenever a signal is received. More documentation can be
/// found on `Signal` itself, but to reiterate:
@@ -281,17 +381,15 @@ impl Signal {
/// * If the previous initialization of this specific signal failed.
/// * If the signal is one of
/// [`signal_hook::FORBIDDEN`](https://docs.rs/signal-hook/*/signal_hook/fn.register.html#panics)
- pub fn new(signal: c_int) -> io::Result<Self> {
- Signal::with_handle(signal, &Handle::default())
+ pub fn new(kind: SignalKind) -> io::Result<Self> {
+ Signal::with_handle(kind, &Handle::default())
}
/// Creates a new stream which will receive notifications when the current
/// process receives the signal `signal`.
///
/// This function will create a new stream which may be based on the
- /// event loop handle provided. This function returns a future which will
- /// then resolve to the signal stream, if successful.
- ///
+ /// provided reactor handle.
/// The `Signal` stream is an infinite stream which will receive
/// notifications whenever a signal is received. More documentation can be
/// found on `Signal` itself, but to reiterate:
@@ -303,7 +401,9 @@ impl Signal {
/// A `Signal` stream can be created for a particular signal number
/// multiple times. When a signal is received then all the associated
/// channels will receive the signal notification.
- pub fn with_handle(signal: c_int, handle: &Handle) -> io::Result<Self> {
+ pub fn with_handle(kind: SignalKind, handle: &Handle) -> io::Result<Self> {
+ let signal = kind.0;
+
// Turn the signal delivery on once we are ready for it
signal_enable(signal)?;
@@ -320,7 +420,7 @@ impl Signal {
}
pub(crate) fn ctrl_c(handle: &Handle) -> io::Result<Self> {
- Self::with_handle(libc::SIGINT, handle)
+ Self::with_handle(SignalKind::sigint(), handle)
}
}
diff --git a/tokio-signal/tests/drop_multi_loop.rs b/tokio-signal/tests/drop_multi_loop.rs
index fa04bc07..c83cf72d 100644
--- a/tokio-signal/tests/drop_multi_loop.rs
+++ b/tokio-signal/tests/drop_multi_loop.rs
@@ -6,18 +6,18 @@ use libc;
pub mod support;
use crate::support::*;
-const TEST_SIGNAL: libc::c_int = libc::SIGUSR1;
-
#[test]
fn dropping_loops_does_not_cause_starvation() {
let (mut rt, signal) = {
+ let kind = SignalKind::sigusr1();
+
let mut first_rt = CurrentThreadRuntime::new().expect("failed to init first runtime");
- let mut first_signal = Signal::new(TEST_SIGNAL).expect("failed to register first signal");
+ let mut first_signal = Signal::new(kind).expect("failed to register first signal");
let mut second_rt = CurrentThreadRuntime::new().expect("failed to init second runtime");
- let mut second_signal = Signal::new(TEST_SIGNAL).expect("failed to register second signal");
+ let mut second_signal = Signal::new(kind).expect("failed to register second signal");
- send_signal(TEST_SIGNAL);
+ send_signal(libc::SIGUSR1);
let _ = run_with_timeout(&mut first_rt, first_signal.next())
.expect("failed to await first signal");
@@ -31,7 +31,7 @@ fn dropping_loops_does_not_cause_starvation() {
(second_rt, second_signal)
};
- send_signal(TEST_SIGNAL);
+ send_signal(libc::SIGUSR1);
let _ = run_with_timeout(&mut rt, signal.into_future());
}
diff --git a/tokio-signal/tests/drop_then_get_a_signal.rs b/tokio-signal/tests/drop_then_get_a_signal.rs
index 0573d6b9..3782474b 100644
--- a/tokio-signal/tests/drop_then_get_a_signal.rs
+++ b/tokio-signal/tests/drop_then_get_a_signal.rs
@@ -9,11 +9,12 @@ use crate::support::*;
#[tokio::test]
async fn drop_then_get_a_signal() {
- let signal = Signal::new(libc::SIGUSR1).expect("failed to create first signal");
+ let kind = SignalKind::sigusr1();
+ let signal = Signal::new(kind).expect("failed to create first signal");
drop(signal);
send_signal(libc::SIGUSR1);
- let signal = Signal::new(libc::SIGUSR1).expect("failed to create second signal");
+ let signal = Signal::new(kind).expect("failed to create second signal");
let _ = with_timeout(signal.into_future()).await;
}
diff --git a/tokio-signal/tests/dropping_does_not_deregister_other_instances.rs b/tokio-signal/tests/dropping_does_not_deregister_other_instances.rs
index 2b80d114..277a3c91 100644
--- a/tokio-signal/tests/dropping_does_not_deregister_other_instances.rs
+++ b/tokio-signal/tests/dropping_does_not_deregister_other_instances.rs
@@ -7,21 +7,21 @@ use libc;
pub mod support;
use crate::support::*;
-const TEST_SIGNAL: libc::c_int = libc::SIGUSR1;
-
#[tokio::test]
async fn dropping_signal_does_not_deregister_any_other_instances() {
+ let kind = SignalKind::sigusr1();
+
// NB: Testing for issue alexcrichton/tokio-signal#38:
// signals should not starve based on ordering
let first_duplicate_signal =
- Signal::new(TEST_SIGNAL).expect("failed to register first duplicate signal");
- let signal = Signal::new(TEST_SIGNAL).expect("failed to register signal");
+ Signal::new(kind).expect("failed to register first duplicate signal");
+ let signal = Signal::new(kind).expect("failed to register signal");
let second_duplicate_signal =
- Signal::new(TEST_SIGNAL).expect("failed to register second duplicate signal");
+ Signal::new(kind).expect("failed to register second duplicate signal");
drop(first_duplicate_signal);
drop(second_duplicate_signal);
- send_signal(TEST_SIGNAL);
+ send_signal(libc::SIGUSR1);
let _ = with_timeout(signal.into_future()).await;
}
diff --git a/tokio-signal/tests/multi_loop.rs b/tokio-signal/tests/multi_loop.rs
index 2fbf4415..f8d32d37 100644
--- a/tokio-signal/tests/multi_loop.rs
+++ b/tokio-signal/tests/multi_loop.rs
@@ -20,7 +20,7 @@ fn multi_loop() {
let sender = sender.clone();
thread::spawn(move || {
let mut rt = CurrentThreadRuntime::new().unwrap();
- let signal = Signal::new(libc::SIGHUP).unwrap();
+ let signal = Signal::new(SignalKind::sighup()).unwrap();
sender.send(()).unwrap();
let _ = run_with_timeout(&mut rt, signal.into_future());
})
diff --git a/tokio-signal/tests/notify_both.rs b/tokio-signal/tests/notify_both.rs
index 9927bf05..5237b9ad 100644
--- a/tokio-signal/tests/notify_both.rs
+++ b/tokio-signal/tests/notify_both.rs
@@ -9,9 +9,10 @@ use libc;
#[tokio::test]
async fn notify_both() {
- let signal1 = Signal::new(libc::SIGUSR2).expect("failed to create signal1");
+ let kind = SignalKind::sigusr2();
+ let signal1 = Signal::new(kind).expect("failed to create signal1");
- let signal2 = Signal::new(libc::SIGUSR2).expect("failed to create signal2");
+ let signal2 = Signal::new(kind).expect("failed to create signal2");
send_signal(libc::SIGUSR2);
let _ = with_timeout(future::join(signal1.into_future(), signal2.into_future())).await;
diff --git a/tokio-signal/tests/simple.rs b/tokio-signal/tests/simple.rs
index 9eafe596..39cdf54a 100644
--- a/tokio-signal/tests/simple.rs
+++ b/tokio-signal/tests/simple.rs
@@ -9,7 +9,7 @@ use libc;
#[tokio::test]
async fn simple() {
- let signal = Signal::new(libc::SIGUSR1).expect("failed to create signal");
+ let signal = Signal::new(SignalKind::sigusr1()).expect("failed to create signal");
send_signal(libc::SIGUSR1);
diff --git a/tokio-signal/tests/support.rs b/tokio-signal/tests/support.rs
index ee6387a5..1d539f1d 100644
--- a/tokio-signal/tests/support.rs
+++ b/tokio-signal/tests/support.rs
@@ -10,7 +10,7 @@ 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;
+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)
diff --git a/tokio-signal/tests/twice.rs b/tokio-signal/tests/twice.rs
index edef0d0c..3a52e411 100644
--- a/tokio-signal/tests/twice.rs
+++ b/tokio-signal/tests/twice.rs
@@ -9,7 +9,8 @@ use libc;
#[tokio::test]
async fn twice() {
- let mut signal = Signal::new(libc::SIGUSR1).expect("failed to get signal");
+ let kind = SignalKind::sigusr1();
+ let mut signal = Signal::new(kind).expect("failed to get signal");
for _ in 0..2 {
send_signal(libc::SIGUSR1);