mirror of
https://github.com/tokio-rs/tokio.git
synced 2026-08-11 00:00:16 +02:00
signal: Add (failing) test case which exibits starvation on drop
* Currently, whenever a new signal stream is created we attempt to register a global pipe with the event loop to drive events. * We also (correctly) swallow any descriptor-already-registered errors since the same pipe is always used * However, we currently *deregister* the same global pipe *any time* a Signal stream is dropped. * This means that if 2 or more of Signal instances exist simultaneously (even if listening for different signals) and one of them is dropped, the remainder will starve (until any new signal is created again).
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
#![cfg(unix)]
|
||||
|
||||
extern crate futures;
|
||||
extern crate libc;
|
||||
extern crate tokio;
|
||||
extern crate tokio_signal;
|
||||
|
||||
use futures::stream::Stream;
|
||||
use futures::Future;
|
||||
use tokio_signal::unix::Signal;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
#[test]
|
||||
fn dropping_signal_does_not_deregister_any_other_instances() {
|
||||
// NB: Deadline requires a timer registration which is provided by
|
||||
// tokio's `current_thread::Runtime`, but isn't available by just using
|
||||
// tokio's default CurrentThread executor which powers `current_thread::block_on_all`.
|
||||
let mut rt = tokio::runtime::current_thread::Runtime::new()
|
||||
.expect("failed to init runtime");
|
||||
|
||||
// FIXME(38): there appears to be a bug with the order these are created/destroyed
|
||||
// If the duplicate signal is created first and dropped, it appears that `signal`
|
||||
// will starve. This ordering also appears to be OS specific...
|
||||
let first_signal = rt.block_on(Signal::new(libc::SIGUSR1))
|
||||
.expect("failed to register duplicate signal");
|
||||
let second_signal = rt.block_on(Signal::new(libc::SIGUSR1))
|
||||
.expect("failed to register signal");
|
||||
let (duplicate, signal) = if cfg!(target_os = "linux") {
|
||||
(second_signal, first_signal)
|
||||
} else {
|
||||
// macOS
|
||||
(first_signal, second_signal)
|
||||
};
|
||||
|
||||
drop(duplicate);
|
||||
|
||||
unsafe { assert_eq!(libc::kill(libc::getpid(), libc::SIGUSR1), 0); }
|
||||
|
||||
let signal_future = signal.into_future()
|
||||
.map_err(|(e, _)| e);
|
||||
|
||||
let deadline_time = Instant::now() + Duration::from_secs(1);
|
||||
rt.block_on(tokio::timer::Deadline::new(signal_future, deadline_time))
|
||||
.expect("failed to get signal");
|
||||
}
|
||||
Reference in New Issue
Block a user