Files
tokio/tokio/src/runtime/threadpool/background.rs
T
Carl Lerche 9d3e5aac08 tokio: remove Send + 'static requirement from block_on (#1329)
Removes the `Send` requirement to futures passed to `Runtime::block_on`.
Previously, `block_on` was implemented by sending the future to a
runtime thread. In order to do this, the future must be Send.

The reason why the future is sent to the pool is because we cannot
guarantee, while off the pool, that a reactor / timer thread is running.
This is due to a limitation in the current version of tokio-threadpool.
There is a plan to fix this (#1177), but the proper fix is non trivial.

In order to unblock APIs that require this, this patch updates the
runtime to spawn an always running thread containing a reactor and
timer. All calls to `block_on` will use that reactor and timer.
2019-07-19 17:25:04 -07:00

62 lines
1.5 KiB
Rust

//! Temporary reactor + timer that runs on a background thread. This it to make
//! `block_on` work.
use tokio_current_thread::CurrentThread;
use tokio_reactor::Reactor;
use tokio_sync::oneshot;
use tokio_timer::clock::Clock;
use tokio_timer::timer::{self, Timer};
use std::{io, thread};
#[derive(Debug)]
pub struct Background {
reactor_handle: tokio_reactor::Handle,
timer_handle: timer::Handle,
shutdown_tx: Option<oneshot::Sender<()>>,
thread: Option<thread::JoinHandle<()>>,
}
pub fn spawn(clock: &Clock) -> io::Result<Background> {
let clock = clock.clone();
let reactor = Reactor::new()?;
let reactor_handle = reactor.handle();
let timer = Timer::new_with_now(reactor, clock);
let timer_handle = timer.handle();
let (shutdown_tx, shutdown_rx) = oneshot::channel();
let shutdown_tx = Some(shutdown_tx);
let thread = thread::spawn(move || {
let mut rt = CurrentThread::new_with_park(timer);
let _ = rt.block_on(shutdown_rx);
});
let thread = Some(thread);
Ok(Background {
reactor_handle,
timer_handle,
shutdown_tx,
thread,
})
}
impl Background {
pub(super) fn reactor(&self) -> &tokio_reactor::Handle {
&self.reactor_handle
}
pub(super) fn timer(&self) -> &timer::Handle {
&self.timer_handle
}
}
impl Drop for Background {
fn drop(&mut self) {
let _ = self.shutdown_tx.take().unwrap().send(());
let _ = self.thread.take().unwrap().join();
}
}