mirror of
https://github.com/tokio-rs/tokio.git
synced 2026-09-02 00:00:11 +02:00
signal: remove new() constructors in favor of free functions (#1472)
* Also removed any `*_with_handle` related methods in favor of always using the default reactor
This commit is contained in:
@@ -1,8 +1,7 @@
|
|||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
use super::unix::Signal as Inner;
|
use super::unix::{self as os_impl, Signal as Inner};
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
use super::windows::Event as Inner;
|
use super::windows::{self as os_impl, Event as Inner};
|
||||||
use crate::driver::Handle;
|
|
||||||
|
|
||||||
use futures_core::stream::Stream;
|
use futures_core::stream::Stream;
|
||||||
use std::io;
|
use std::io;
|
||||||
@@ -30,22 +29,12 @@ pub struct CtrlC {
|
|||||||
inner: Inner,
|
inner: Inner,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CtrlC {
|
/// Creates a new stream which receives "ctrl-c" notifications sent to the
|
||||||
/// Creates a new stream which receives "ctrl-c" notifications sent to the
|
/// process.
|
||||||
/// process.
|
///
|
||||||
///
|
/// This function binds to the default reactor.
|
||||||
/// This function binds to the default reactor.
|
pub fn ctrl_c() -> io::Result<CtrlC> {
|
||||||
pub fn new() -> io::Result<Self> {
|
os_impl::ctrl_c().map(|inner| CtrlC { inner })
|
||||||
Self::with_handle(&Handle::default())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a new stream which receives "ctrl-c" notifications sent to the
|
|
||||||
/// process.
|
|
||||||
///
|
|
||||||
/// This function binds to reactor specified by `handle`.
|
|
||||||
pub fn with_handle(handle: &Handle) -> io::Result<Self> {
|
|
||||||
Inner::ctrl_c(handle).map(|inner| Self { inner })
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Stream for CtrlC {
|
impl Stream for CtrlC {
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
//! // Create an infinite stream of "Ctrl+C" notifications. Each item received
|
//! // Create an infinite stream of "Ctrl+C" notifications. Each item received
|
||||||
//! // on this stream may represent multiple ctrl-c signals.
|
//! // on this stream may represent multiple ctrl-c signals.
|
||||||
//! let ctrl_c = signal::CtrlC::new()?;
|
//! let ctrl_c = signal::ctrl_c()?;
|
||||||
//!
|
//!
|
||||||
//! // Process each ctrl-c as it comes in
|
//! // Process each ctrl-c as it comes in
|
||||||
//! let prog = ctrl_c.for_each(|_| {
|
//! let prog = ctrl_c.for_each(|_| {
|
||||||
@@ -49,7 +49,7 @@
|
|||||||
//! #![feature(async_await)]
|
//! #![feature(async_await)]
|
||||||
//! # #[cfg(unix)] {
|
//! # #[cfg(unix)] {
|
||||||
//!
|
//!
|
||||||
//! use tokio_net::signal::{self, unix::{Signal, SignalKind}};
|
//! use tokio_net::signal::{self, unix::{signal, SignalKind}};
|
||||||
//!
|
//!
|
||||||
//! use futures_util::future;
|
//! use futures_util::future;
|
||||||
//! use futures_util::stream::StreamExt;
|
//! use futures_util::stream::StreamExt;
|
||||||
@@ -58,7 +58,7 @@
|
|||||||
//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
//! // Create an infinite stream of "Ctrl+C" notifications. Each item received
|
//! // Create an infinite stream of "Ctrl+C" notifications. Each item received
|
||||||
//! // on this stream may represent multiple ctrl-c signals.
|
//! // on this stream may represent multiple ctrl-c signals.
|
||||||
//! let ctrl_c = signal::CtrlC::new()?;
|
//! let ctrl_c = signal::ctrl_c()?;
|
||||||
//!
|
//!
|
||||||
//! // Process each ctrl-c as it comes in
|
//! // Process each ctrl-c as it comes in
|
||||||
//! let prog = ctrl_c.for_each(|_| {
|
//! let prog = ctrl_c.for_each(|_| {
|
||||||
@@ -70,10 +70,10 @@
|
|||||||
//!
|
//!
|
||||||
//! // Like the previous example, this is an infinite stream of signals
|
//! // Like the previous example, this is an infinite stream of signals
|
||||||
//! // being received, and signals may be coalesced while pending.
|
//! // being received, and signals may be coalesced while pending.
|
||||||
//! let stream = Signal::new(SignalKind::hangup())?;
|
//! let stream = signal(SignalKind::hangup())?;
|
||||||
//!
|
//!
|
||||||
//! // Convert out stream into a future and block the program
|
//! // Convert out stream into a future and block the program
|
||||||
//! let (signal, _signal) = stream.into_future().await;
|
//! let (signal, _stream) = stream.into_future().await;
|
||||||
//! println!("got signal {:?}", signal);
|
//! println!("got signal {:?}", signal);
|
||||||
//! Ok(())
|
//! Ok(())
|
||||||
//! }
|
//! }
|
||||||
@@ -93,4 +93,4 @@ mod os {
|
|||||||
pub mod unix;
|
pub mod unix;
|
||||||
pub mod windows;
|
pub mod windows;
|
||||||
|
|
||||||
pub use self::ctrl_c::CtrlC;
|
pub use self::ctrl_c::{ctrl_c, CtrlC};
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
#![cfg(unix)]
|
#![cfg(unix)]
|
||||||
|
|
||||||
use super::registry::{globals, EventId, EventInfo, Globals, Init, Storage};
|
use super::registry::{globals, EventId, EventInfo, Globals, Init, Storage};
|
||||||
use crate::driver::Handle;
|
|
||||||
use crate::util::PollEvented;
|
use crate::util::PollEvented;
|
||||||
|
|
||||||
use tokio_io::AsyncRead;
|
use tokio_io::AsyncRead;
|
||||||
@@ -280,7 +279,7 @@ impl Future for Driver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Driver {
|
impl Driver {
|
||||||
fn new(handle: &Handle) -> io::Result<Driver> {
|
fn new() -> io::Result<Driver> {
|
||||||
// NB: We give each driver a "fresh" reciever file descriptor to avoid
|
// NB: We give each driver a "fresh" reciever file descriptor to avoid
|
||||||
// the issues described in alexcrichton/tokio-process#42.
|
// the issues described in alexcrichton/tokio-process#42.
|
||||||
//
|
//
|
||||||
@@ -295,7 +294,7 @@ impl Driver {
|
|||||||
// either, since we can't compare Handles or assume they will always
|
// either, since we can't compare Handles or assume they will always
|
||||||
// point to the exact same reactor.
|
// point to the exact same reactor.
|
||||||
let stream = globals().receiver.try_clone()?;
|
let stream = globals().receiver.try_clone()?;
|
||||||
let wakeup = PollEvented::new_with_handle(stream, handle)?;
|
let wakeup = PollEvented::new(stream);
|
||||||
|
|
||||||
Ok(Driver { wakeup })
|
Ok(Driver { wakeup })
|
||||||
}
|
}
|
||||||
@@ -359,70 +358,48 @@ pub struct Signal {
|
|||||||
rx: Receiver<()>,
|
rx: Receiver<()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Signal {
|
/// Creates a new stream which will receive notifications when the current
|
||||||
/// Creates a new stream which will receive notifications when the current
|
/// process receives the signal `signal`.
|
||||||
/// process receives the signal `signal`.
|
///
|
||||||
///
|
/// This function will create a new stream which binds to the default reactor.
|
||||||
/// This function will create a new stream which binds to the default reactor.
|
/// The `Signal` stream is an infinite stream which will receive
|
||||||
/// The `Signal` stream is an infinite stream which will receive
|
/// notifications whenever a signal is received. More documentation can be
|
||||||
/// notifications whenever a signal is received. More documentation can be
|
/// found on `Signal` itself, but to reiterate:
|
||||||
/// found on `Signal` itself, but to reiterate:
|
///
|
||||||
///
|
/// * Signals may be coalesced beyond what the kernel already does.
|
||||||
/// * Signals may be coalesced beyond what the kernel already does.
|
/// * Once a signal handler is registered with the process the underlying
|
||||||
/// * Once a signal handler is registered with the process the underlying
|
/// libc signal handler is never unregistered.
|
||||||
/// libc signal handler is never unregistered.
|
///
|
||||||
///
|
/// A `Signal` stream can be created for a particular signal number
|
||||||
/// A `Signal` stream can be created for a particular signal number
|
/// multiple times. When a signal is received then all the associated
|
||||||
/// multiple times. When a signal is received then all the associated
|
/// channels will receive the signal notification.
|
||||||
/// channels will receive the signal notification.
|
///
|
||||||
///
|
/// # Errors
|
||||||
/// # Errors
|
///
|
||||||
///
|
/// * If the lower-level C functions fail for some reason.
|
||||||
/// * If the lower-level C functions fail for some reason.
|
/// * If the previous initialization of this specific signal failed.
|
||||||
/// * If the previous initialization of this specific signal failed.
|
/// * If the signal is one of
|
||||||
/// * If the signal is one of
|
/// [`signal_hook::FORBIDDEN`](https://docs.rs/signal-hook/*/signal_hook/fn.register.html#panics)
|
||||||
/// [`signal_hook::FORBIDDEN`](https://docs.rs/signal-hook/*/signal_hook/fn.register.html#panics)
|
pub fn signal(kind: SignalKind) -> io::Result<Signal> {
|
||||||
pub fn new(kind: SignalKind) -> io::Result<Self> {
|
let signal = kind.0;
|
||||||
Signal::with_handle(kind, &Handle::default())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a new stream which will receive notifications when the current
|
// Turn the signal delivery on once we are ready for it
|
||||||
/// process receives the signal `signal`.
|
signal_enable(signal)?;
|
||||||
///
|
|
||||||
/// This function will create a new stream which may be based on the
|
|
||||||
/// 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:
|
|
||||||
///
|
|
||||||
/// * Signals may be coalesced beyond what the kernel already does.
|
|
||||||
/// * Once a signal handler is registered with the process the underlying
|
|
||||||
/// libc signal handler is never unregistered.
|
|
||||||
///
|
|
||||||
/// 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(kind: SignalKind, handle: &Handle) -> io::Result<Self> {
|
|
||||||
let signal = kind.0;
|
|
||||||
|
|
||||||
// Turn the signal delivery on once we are ready for it
|
// Ensure there's a driver for our associated event loop processing
|
||||||
signal_enable(signal)?;
|
// signals.
|
||||||
|
let driver = Driver::new()?;
|
||||||
|
|
||||||
// Ensure there's a driver for our associated event loop processing
|
// One wakeup in a queue is enough, no need for us to buffer up any
|
||||||
// signals.
|
// more.
|
||||||
let driver = Driver::new(&handle)?;
|
let (tx, rx) = channel(1);
|
||||||
|
globals().register_listener(signal as EventId, tx);
|
||||||
|
|
||||||
// One wakeup in a queue is enough, no need for us to buffer up any
|
Ok(Signal { driver, rx })
|
||||||
// more.
|
}
|
||||||
let (tx, rx) = channel(1);
|
|
||||||
globals().register_listener(signal as EventId, tx);
|
|
||||||
|
|
||||||
Ok(Signal { driver, rx })
|
pub(crate) fn ctrl_c() -> io::Result<Signal> {
|
||||||
}
|
signal(SignalKind::interrupt())
|
||||||
|
|
||||||
pub(crate) fn ctrl_c(handle: &Handle) -> io::Result<Self> {
|
|
||||||
Self::with_handle(SignalKind::interrupt(), handle)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Stream for Signal {
|
impl Stream for Signal {
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
#![cfg(windows)]
|
#![cfg(windows)]
|
||||||
|
|
||||||
use super::registry::{globals, EventId, EventInfo, Init, Storage};
|
use super::registry::{globals, EventId, EventInfo, Init, Storage};
|
||||||
use crate::driver::Handle;
|
|
||||||
|
|
||||||
use tokio_sync::mpsc::{channel, Receiver};
|
use tokio_sync::mpsc::{channel, Receiver};
|
||||||
|
|
||||||
@@ -85,23 +84,7 @@ pub(crate) struct Event {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Event {
|
impl Event {
|
||||||
/// Creates a new stream listening for the `CTRL_C_EVENT` events.
|
fn new(signum: DWORD) -> io::Result<Self> {
|
||||||
///
|
|
||||||
/// This function will register a handler via `SetConsoleCtrlHandler` and
|
|
||||||
/// deliver notifications to the returned stream.
|
|
||||||
pub(crate) fn ctrl_c(handle: &Handle) -> io::Result<Self> {
|
|
||||||
Event::new(CTRL_C_EVENT, handle)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a new stream listening for the `CTRL_BREAK_EVENT` events.
|
|
||||||
///
|
|
||||||
/// This function will register a handler via `SetConsoleCtrlHandler` and
|
|
||||||
/// deliver notifications to the returned stream.
|
|
||||||
fn ctrl_break_handle(handle: &Handle) -> io::Result<Self> {
|
|
||||||
Event::new(CTRL_BREAK_EVENT, handle)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new(signum: DWORD, _handle: &Handle) -> io::Result<Self> {
|
|
||||||
global_init()?;
|
global_init()?;
|
||||||
|
|
||||||
let (tx, rx) = channel(1);
|
let (tx, rx) = channel(1);
|
||||||
@@ -111,6 +94,10 @@ impl Event {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn ctrl_c() -> io::Result<Event> {
|
||||||
|
Event::new(CTRL_C_EVENT)
|
||||||
|
}
|
||||||
|
|
||||||
impl Stream for Event {
|
impl Stream for Event {
|
||||||
type Item = ();
|
type Item = ();
|
||||||
|
|
||||||
@@ -167,22 +154,12 @@ pub struct CtrlBreak {
|
|||||||
inner: Event,
|
inner: Event,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CtrlBreak {
|
/// Creates a new stream which receives "ctrl-break" notifications sent to the
|
||||||
/// Creates a new stream which receives "ctrl-break" notifications sent to the
|
/// process.
|
||||||
/// process.
|
///
|
||||||
///
|
/// This function binds to the default reactor.
|
||||||
/// This function binds to the default reactor.
|
pub fn ctrl_break() -> io::Result<CtrlBreak> {
|
||||||
pub fn new() -> io::Result<Self> {
|
Event::new(CTRL_BREAK_EVENT).map(|inner| CtrlBreak { inner })
|
||||||
Self::with_handle(&Handle::default())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a new stream which receives "ctrl-break" notifications sent to the
|
|
||||||
/// process.
|
|
||||||
///
|
|
||||||
/// This function binds to reactor specified by `handle`.
|
|
||||||
pub fn with_handle(handle: &Handle) -> io::Result<Self> {
|
|
||||||
Event::ctrl_break_handle(handle).map(|inner| Self { inner })
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Stream for CtrlBreak {
|
impl Stream for CtrlBreak {
|
||||||
@@ -212,7 +189,7 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn ctrl_c() {
|
async fn ctrl_c() {
|
||||||
let ctrl_c = crate::signal::CtrlC::new().expect("failed to create CtrlC");
|
let ctrl_c = crate::signal::ctrl_c().expect("failed to create CtrlC");
|
||||||
|
|
||||||
// Windows doesn't have a good programmatic way of sending events
|
// Windows doesn't have a good programmatic way of sending events
|
||||||
// like sending signals on Unix, so we'll stub out the actual OS
|
// like sending signals on Unix, so we'll stub out the actual OS
|
||||||
@@ -226,7 +203,7 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn ctrl_break() {
|
async fn ctrl_break() {
|
||||||
let ctrl_break = super::CtrlBreak::new().expect("failed to create CtrlC");
|
let ctrl_break = super::ctrl_break().expect("failed to create CtrlC");
|
||||||
|
|
||||||
// Windows doesn't have a good programmatic way of sending events
|
// Windows doesn't have a good programmatic way of sending events
|
||||||
// like sending signals on Unix, so we'll stub out the actual OS
|
// like sending signals on Unix, so we'll stub out the actual OS
|
||||||
|
|||||||
@@ -11,10 +11,10 @@ fn dropping_loops_does_not_cause_starvation() {
|
|||||||
let kind = SignalKind::user_defined1();
|
let kind = SignalKind::user_defined1();
|
||||||
|
|
||||||
let mut first_rt = CurrentThreadRuntime::new().expect("failed to init first runtime");
|
let mut first_rt = CurrentThreadRuntime::new().expect("failed to init first runtime");
|
||||||
let mut first_signal = Signal::new(kind).expect("failed to register first signal");
|
let mut first_signal = signal(kind).expect("failed to register first signal");
|
||||||
|
|
||||||
let mut second_rt = CurrentThreadRuntime::new().expect("failed to init second runtime");
|
let mut second_rt = CurrentThreadRuntime::new().expect("failed to init second runtime");
|
||||||
let mut second_signal = Signal::new(kind).expect("failed to register second signal");
|
let mut second_signal = signal(kind).expect("failed to register second signal");
|
||||||
|
|
||||||
send_signal(libc::SIGUSR1);
|
send_signal(libc::SIGUSR1);
|
||||||
|
|
||||||
|
|||||||
@@ -9,11 +9,11 @@ use crate::signal_support::*;
|
|||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn drop_then_get_a_signal() {
|
async fn drop_then_get_a_signal() {
|
||||||
let kind = SignalKind::user_defined1();
|
let kind = SignalKind::user_defined1();
|
||||||
let signal = Signal::new(kind).expect("failed to create first signal");
|
let sig = signal(kind).expect("failed to create first signal");
|
||||||
drop(signal);
|
drop(sig);
|
||||||
|
|
||||||
send_signal(libc::SIGUSR1);
|
send_signal(libc::SIGUSR1);
|
||||||
let signal = Signal::new(kind).expect("failed to create second signal");
|
let sig = signal(kind).expect("failed to create second signal");
|
||||||
|
|
||||||
let _ = with_timeout(signal.into_future()).await;
|
let _ = with_timeout(sig.into_future()).await;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,15 +12,13 @@ async fn dropping_signal_does_not_deregister_any_other_instances() {
|
|||||||
|
|
||||||
// NB: Testing for issue alexcrichton/tokio-signal#38:
|
// NB: Testing for issue alexcrichton/tokio-signal#38:
|
||||||
// signals should not starve based on ordering
|
// signals should not starve based on ordering
|
||||||
let first_duplicate_signal =
|
let first_duplicate_signal = signal(kind).expect("failed to register first duplicate signal");
|
||||||
Signal::new(kind).expect("failed to register first duplicate signal");
|
let sig = signal(kind).expect("failed to register signal");
|
||||||
let signal = Signal::new(kind).expect("failed to register signal");
|
let second_duplicate_signal = signal(kind).expect("failed to register second duplicate signal");
|
||||||
let second_duplicate_signal =
|
|
||||||
Signal::new(kind).expect("failed to register second duplicate signal");
|
|
||||||
|
|
||||||
drop(first_duplicate_signal);
|
drop(first_duplicate_signal);
|
||||||
drop(second_duplicate_signal);
|
drop(second_duplicate_signal);
|
||||||
|
|
||||||
send_signal(libc::SIGUSR1);
|
send_signal(libc::SIGUSR1);
|
||||||
let _ = with_timeout(signal.into_future()).await;
|
let _ = with_timeout(sig.into_future()).await;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ fn multi_loop() {
|
|||||||
let sender = sender.clone();
|
let sender = sender.clone();
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
let mut rt = CurrentThreadRuntime::new().unwrap();
|
let mut rt = CurrentThreadRuntime::new().unwrap();
|
||||||
let signal = Signal::new(SignalKind::hangup()).unwrap();
|
let signal = signal(SignalKind::hangup()).unwrap();
|
||||||
sender.send(()).unwrap();
|
sender.send(()).unwrap();
|
||||||
let _ = run_with_timeout(&mut rt, signal.into_future());
|
let _ = run_with_timeout(&mut rt, signal.into_future());
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ use crate::signal_support::*;
|
|||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn notify_both() {
|
async fn notify_both() {
|
||||||
let kind = SignalKind::user_defined2();
|
let kind = SignalKind::user_defined2();
|
||||||
let signal1 = Signal::new(kind).expect("failed to create signal1");
|
let signal1 = signal(kind).expect("failed to create signal1");
|
||||||
|
|
||||||
let signal2 = Signal::new(kind).expect("failed to create signal2");
|
let signal2 = signal(kind).expect("failed to create signal2");
|
||||||
|
|
||||||
send_signal(libc::SIGUSR2);
|
send_signal(libc::SIGUSR2);
|
||||||
let _ = with_timeout(future::join(signal1.into_future(), signal2.into_future())).await;
|
let _ = with_timeout(future::join(signal1.into_future(), signal2.into_future())).await;
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use crate::signal_support::*;
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn simple() {
|
async fn simple() {
|
||||||
let signal = Signal::new(SignalKind::user_defined1()).expect("failed to create signal");
|
let signal = signal(SignalKind::user_defined1()).expect("failed to create signal");
|
||||||
|
|
||||||
send_signal(libc::SIGUSR1);
|
send_signal(libc::SIGUSR1);
|
||||||
|
|
||||||
@@ -19,9 +19,9 @@ async fn simple() {
|
|||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
async fn ctrl_c() {
|
async fn ctrl_c() {
|
||||||
use tokio::sync::oneshot;
|
use tokio::sync::oneshot;
|
||||||
use tokio_net::signal::CtrlC;
|
use tokio_net::signal::ctrl_c;
|
||||||
|
|
||||||
let ctrl_c = CtrlC::new().expect("failed to init ctrl_c");
|
let ctrl_c = ctrl_c().expect("failed to init ctrl_c");
|
||||||
|
|
||||||
let (fire, wait) = oneshot::channel();
|
let (fire, wait) = oneshot::channel();
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
pub use tokio::runtime::current_thread::{self, Runtime as CurrentThreadRuntime};
|
pub use tokio::runtime::current_thread::{self, Runtime as CurrentThreadRuntime};
|
||||||
use tokio::timer::Timeout;
|
use tokio::timer::Timeout;
|
||||||
pub use tokio_net::signal::unix::{Signal, SignalKind};
|
pub use tokio_net::signal::unix::{signal, SignalKind};
|
||||||
|
|
||||||
pub use futures_util::future;
|
pub use futures_util::future;
|
||||||
use futures_util::future::FutureExt;
|
use futures_util::future::FutureExt;
|
||||||
|
|||||||
@@ -9,14 +9,14 @@ use crate::signal_support::*;
|
|||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn twice() {
|
async fn twice() {
|
||||||
let kind = SignalKind::user_defined1();
|
let kind = SignalKind::user_defined1();
|
||||||
let mut signal = Signal::new(kind).expect("failed to get signal");
|
let mut sig = signal(kind).expect("failed to get signal");
|
||||||
|
|
||||||
for _ in 0..2 {
|
for _ in 0..2 {
|
||||||
send_signal(libc::SIGUSR1);
|
send_signal(libc::SIGUSR1);
|
||||||
|
|
||||||
let (item, sig) = with_timeout(signal.into_future()).await;
|
let (item, sig_next) = with_timeout(sig.into_future()).await;
|
||||||
assert_eq!(item, Some(()));
|
assert_eq!(item, Some(()));
|
||||||
|
|
||||||
signal = sig;
|
sig = sig_next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -146,7 +146,6 @@ use futures_util::try_future::TryFutureExt;
|
|||||||
|
|
||||||
use kill::Kill;
|
use kill::Kill;
|
||||||
use tokio_io::{AsyncRead, AsyncReadExt, AsyncWrite};
|
use tokio_io::{AsyncRead, AsyncReadExt, AsyncWrite};
|
||||||
use tokio_net::driver::Handle;
|
|
||||||
|
|
||||||
#[path = "unix/mod.rs"]
|
#[path = "unix/mod.rs"]
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
@@ -493,24 +492,7 @@ impl Command {
|
|||||||
/// .expect("ls command failed to run")
|
/// .expect("ls command failed to run")
|
||||||
/// }
|
/// }
|
||||||
pub fn spawn(&mut self) -> io::Result<Child> {
|
pub fn spawn(&mut self) -> io::Result<Child> {
|
||||||
self.spawn_with_handle(&Handle::default())
|
imp::spawn_child(&mut self.std).map(|spawned_child| Child {
|
||||||
}
|
|
||||||
|
|
||||||
/// Executes the command as a child process, returning a handle to it.
|
|
||||||
///
|
|
||||||
/// By default, stdin, stdout and stderr are inherited from the parent.
|
|
||||||
///
|
|
||||||
/// This method will spawn the child process synchronously and return a
|
|
||||||
/// handle to a future-aware child process. The `Child` returned implements
|
|
||||||
/// `Future` itself to acquire the `ExitStatus` of the child, and otherwise
|
|
||||||
/// the `Child` has methods to acquire handles to the stdin, stdout, and
|
|
||||||
/// stderr streams.
|
|
||||||
///
|
|
||||||
/// The `handle` specified to this method must be a handle to a valid event
|
|
||||||
/// loop, and all I/O this child does will be associated with the specified
|
|
||||||
/// event loop.
|
|
||||||
pub fn spawn_with_handle(&mut self, handle: &Handle) -> io::Result<Child> {
|
|
||||||
imp::spawn_child(&mut self.std, handle).map(|spawned_child| Child {
|
|
||||||
child: ChildDropGuard::new(spawned_child.child),
|
child: ChildDropGuard::new(spawned_child.child),
|
||||||
stdin: spawned_child.stdin.map(|inner| ChildStdin { inner }),
|
stdin: spawned_child.stdin.map(|inner| ChildStdin { inner }),
|
||||||
stdout: spawned_child.stdout.map(|inner| ChildStdout { inner }),
|
stdout: spawned_child.stdout.map(|inner| ChildStdout { inner }),
|
||||||
@@ -556,32 +538,7 @@ impl Command {
|
|||||||
/// .expect("ls command failed to run")
|
/// .expect("ls command failed to run")
|
||||||
/// }
|
/// }
|
||||||
pub fn status(&mut self) -> io::Result<StatusAsync> {
|
pub fn status(&mut self) -> io::Result<StatusAsync> {
|
||||||
self.status_with_handle(&Handle::default())
|
self.spawn().map(|mut child| {
|
||||||
}
|
|
||||||
|
|
||||||
/// Executes a command as a child process, waiting for it to finish and
|
|
||||||
/// collecting its exit status.
|
|
||||||
///
|
|
||||||
/// By default, stdin, stdout and stderr are inherited from the parent.
|
|
||||||
///
|
|
||||||
/// The `StatusAsync` future returned will resolve to the `ExitStatus`
|
|
||||||
/// type in the standard library representing how the process exited. If
|
|
||||||
/// any input/output handles are set to a pipe then they will be immediately
|
|
||||||
/// closed after the child is spawned.
|
|
||||||
///
|
|
||||||
/// The `handle` specified must be a handle to a valid event loop, and all
|
|
||||||
/// I/O this child does will be associated with the specified event loop.
|
|
||||||
///
|
|
||||||
/// If the `StatusAsync` future is dropped before the future resolves, then
|
|
||||||
/// the child will be killed, if it was spawned.
|
|
||||||
///
|
|
||||||
/// # Errors
|
|
||||||
///
|
|
||||||
/// This function will return an error immediately if the child process
|
|
||||||
/// cannot be spawned. Otherwise errors obtained while waiting for the child
|
|
||||||
/// are returned through the `StatusAsync` future.
|
|
||||||
pub fn status_with_handle(&mut self, handle: &Handle) -> io::Result<StatusAsync> {
|
|
||||||
self.spawn_with_handle(handle).map(|mut child| {
|
|
||||||
// Ensure we close any stdio handles so we can't deadlock
|
// Ensure we close any stdio handles so we can't deadlock
|
||||||
// waiting on the child which may be waiting to read/write
|
// waiting on the child which may be waiting to read/write
|
||||||
// to a pipe we're holding.
|
// to a pipe we're holding.
|
||||||
@@ -630,34 +587,10 @@ impl Command {
|
|||||||
/// println!("stderr of ls: {:?}", output.stderr);
|
/// println!("stderr of ls: {:?}", output.stderr);
|
||||||
/// }
|
/// }
|
||||||
pub fn output(&mut self) -> OutputAsync {
|
pub fn output(&mut self) -> OutputAsync {
|
||||||
self.output_with_handle(&Handle::default())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Executes the command as a child process, waiting for it to finish and
|
|
||||||
/// collecting all of its output.
|
|
||||||
///
|
|
||||||
/// > **Note**: this method, unlike the standard library, will
|
|
||||||
/// > unconditionally configure the stdout/stderr handles to be pipes, even
|
|
||||||
/// > if they have been previously configured. If this is not desired then
|
|
||||||
/// > the `spawn` method should be used in combination with the
|
|
||||||
/// > `wait_with_output` method on child.
|
|
||||||
///
|
|
||||||
/// This method will return a future representing the collection of the
|
|
||||||
/// child process's stdout/stderr. The `OutputAsync` future will resolve to
|
|
||||||
/// the `Output` type in the standard library, containing `stdout` and
|
|
||||||
/// `stderr` as `Vec<u8>` along with an `ExitStatus` representing how the
|
|
||||||
/// process exited.
|
|
||||||
///
|
|
||||||
/// The `handle` specified must be a handle to a valid event loop, and all
|
|
||||||
/// I/O this child does will be associated with the specified event loop.
|
|
||||||
///
|
|
||||||
/// If the `OutputAsync` future is dropped before the future resolves, then
|
|
||||||
/// the child will be killed, if it was spawned.
|
|
||||||
pub fn output_with_handle(&mut self, handle: &Handle) -> OutputAsync {
|
|
||||||
self.std.stdout(Stdio::piped());
|
self.std.stdout(Stdio::piped());
|
||||||
self.std.stderr(Stdio::piped());
|
self.std.stderr(Stdio::piped());
|
||||||
|
|
||||||
let inner = future::ready(self.spawn_with_handle(handle)).and_then(Child::wait_with_output);
|
let inner = future::ready(self.spawn()).and_then(Child::wait_with_output);
|
||||||
|
|
||||||
OutputAsync {
|
OutputAsync {
|
||||||
inner: inner.boxed(),
|
inner: inner.boxed(),
|
||||||
|
|||||||
@@ -29,8 +29,7 @@ use self::reap::Reaper;
|
|||||||
use super::SpawnedChild;
|
use super::SpawnedChild;
|
||||||
use crate::kill::Kill;
|
use crate::kill::Kill;
|
||||||
|
|
||||||
use tokio_net::driver::Handle;
|
use tokio_net::signal::unix::{signal, Signal, SignalKind};
|
||||||
use tokio_net::signal::unix::{Signal, SignalKind};
|
|
||||||
use tokio_net::util::PollEvented;
|
use tokio_net::util::PollEvented;
|
||||||
|
|
||||||
use mio::event::Evented;
|
use mio::event::Evented;
|
||||||
@@ -96,13 +95,13 @@ impl fmt::Debug for Child {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn spawn_child(cmd: &mut process::Command, handle: &Handle) -> io::Result<SpawnedChild> {
|
pub(crate) fn spawn_child(cmd: &mut process::Command) -> io::Result<SpawnedChild> {
|
||||||
let mut child = cmd.spawn()?;
|
let mut child = cmd.spawn()?;
|
||||||
let stdin = stdio(child.stdin.take(), handle)?;
|
let stdin = stdio(child.stdin.take())?;
|
||||||
let stdout = stdio(child.stdout.take(), handle)?;
|
let stdout = stdio(child.stdout.take())?;
|
||||||
let stderr = stdio(child.stderr.take(), handle)?;
|
let stderr = stdio(child.stderr.take())?;
|
||||||
|
|
||||||
let signal = Signal::with_handle(SignalKind::child(), handle)?;
|
let signal = signal(SignalKind::child())?;
|
||||||
|
|
||||||
Ok(SpawnedChild {
|
Ok(SpawnedChild {
|
||||||
child: Child {
|
child: Child {
|
||||||
@@ -203,7 +202,7 @@ pub(crate) type ChildStdin = PollEvented<Fd<process::ChildStdin>>;
|
|||||||
pub(crate) type ChildStdout = PollEvented<Fd<process::ChildStdout>>;
|
pub(crate) type ChildStdout = PollEvented<Fd<process::ChildStdout>>;
|
||||||
pub(crate) type ChildStderr = PollEvented<Fd<process::ChildStderr>>;
|
pub(crate) type ChildStderr = PollEvented<Fd<process::ChildStderr>>;
|
||||||
|
|
||||||
fn stdio<T>(option: Option<T>, handle: &Handle) -> io::Result<Option<PollEvented<Fd<T>>>>
|
fn stdio<T>(option: Option<T>) -> io::Result<Option<PollEvented<Fd<T>>>>
|
||||||
where
|
where
|
||||||
T: AsRawFd,
|
T: AsRawFd,
|
||||||
{
|
{
|
||||||
@@ -224,6 +223,5 @@ where
|
|||||||
return Err(io::Error::last_os_error());
|
return Err(io::Error::last_os_error());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let io = PollEvented::new_with_handle(Fd { inner: io }, handle)?;
|
Ok(Some(PollEvented::new(Fd { inner: io })))
|
||||||
Ok(Some(io))
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,6 @@
|
|||||||
use super::SpawnedChild;
|
use super::SpawnedChild;
|
||||||
use crate::kill::Kill;
|
use crate::kill::Kill;
|
||||||
|
|
||||||
use tokio_net::driver::Handle;
|
|
||||||
use tokio_net::util::PollEvented;
|
use tokio_net::util::PollEvented;
|
||||||
use tokio_sync::oneshot;
|
use tokio_sync::oneshot;
|
||||||
|
|
||||||
@@ -69,11 +68,11 @@ struct Waiting {
|
|||||||
unsafe impl Sync for Waiting {}
|
unsafe impl Sync for Waiting {}
|
||||||
unsafe impl Send for Waiting {}
|
unsafe impl Send for Waiting {}
|
||||||
|
|
||||||
pub(crate) fn spawn_child(cmd: &mut process::Command, handle: &Handle) -> io::Result<SpawnedChild> {
|
pub(crate) fn spawn_child(cmd: &mut process::Command) -> io::Result<SpawnedChild> {
|
||||||
let mut child = cmd.spawn()?;
|
let mut child = cmd.spawn()?;
|
||||||
let stdin = stdio(child.stdin.take(), handle)?;
|
let stdin = stdio(child.stdin.take());
|
||||||
let stdout = stdio(child.stdout.take(), handle)?;
|
let stdout = stdio(child.stdout.take());
|
||||||
let stderr = stdio(child.stderr.take(), handle)?;
|
let stderr = stdio(child.stderr.take());
|
||||||
|
|
||||||
Ok(SpawnedChild {
|
Ok(SpawnedChild {
|
||||||
child: Child {
|
child: Child {
|
||||||
@@ -182,15 +181,14 @@ pub(crate) type ChildStdin = PollEvented<NamedPipe>;
|
|||||||
pub(crate) type ChildStdout = PollEvented<NamedPipe>;
|
pub(crate) type ChildStdout = PollEvented<NamedPipe>;
|
||||||
pub(crate) type ChildStderr = PollEvented<NamedPipe>;
|
pub(crate) type ChildStderr = PollEvented<NamedPipe>;
|
||||||
|
|
||||||
fn stdio<T>(option: Option<T>, handle: &Handle) -> io::Result<Option<PollEvented<NamedPipe>>>
|
fn stdio<T>(option: Option<T>) -> Option<PollEvented<NamedPipe>>
|
||||||
where
|
where
|
||||||
T: IntoRawHandle,
|
T: IntoRawHandle,
|
||||||
{
|
{
|
||||||
let io = match option {
|
let io = match option {
|
||||||
Some(io) => io,
|
Some(io) => io,
|
||||||
None => return Ok(None),
|
None => return None,
|
||||||
};
|
};
|
||||||
let pipe = unsafe { NamedPipe::from_raw_handle(io.into_raw_handle()) };
|
let pipe = unsafe { NamedPipe::from_raw_handle(io.into_raw_handle()) };
|
||||||
let io = PollEvented::new_with_handle(pipe, handle)?;
|
Some(PollEvented::new(pipe))
|
||||||
Ok(Some(io))
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user