simplify enter (#1736)

This commit is contained in:
Carl Lerche
2019-11-06 09:51:15 -08:00
committed by GitHub
parent 0da23aad77
commit 1a7f6fb201
6 changed files with 31 additions and 59 deletions
+1 -2
View File
@@ -139,8 +139,7 @@ where
let scheduler = &*self.scheduler;
runtime::global::with_current_thread(scheduler, || {
let mut _enter =
runtime::enter::enter().expect("attempting to block while on a Tokio executor");
let mut _enter = runtime::enter();
let raw_waker = RawWaker::new(
scheduler as *const Scheduler as *const (),
+18 -39
View File
@@ -1,5 +1,4 @@
use std::cell::{Cell, RefCell};
use std::error::Error;
use std::fmt;
use std::future::Future;
use std::marker::PhantomData;
@@ -13,50 +12,30 @@ pub(crate) struct Enter {
_p: PhantomData<RefCell<()>>,
}
/// An error returned by `enter` if an execution scope has already been
/// entered.
pub(crate) struct EnterError {
_a: (),
}
impl fmt::Debug for EnterError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("EnterError")
.field("reason", &format!("{}", self))
.finish()
}
}
impl fmt::Display for EnterError {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
fmt,
"attempted to run an executor while another executor is already running"
)
}
}
impl Error for EnterError {}
/// Marks the current thread as being within the dynamic extent of an
/// executor.
///
/// Executor implementations should call this function before blocking the
/// thread. If `None` is returned, the executor should fail by panicking or
/// taking some other action without blocking the current thread. This prevents
/// deadlocks due to multiple executors competing for the same thread.
///
/// # Error
///
/// Returns an error if the current thread is already marked
pub(crate) fn enter() -> Result<Enter, EnterError> {
pub(crate) fn enter() -> Enter {
if let Some(enter) = try_enter() {
return enter;
}
panic!(
"Cannot start a runtime from within a runtime. This happens \
because a function (like `block_on`) attempted to block the \
current thread while the thread is being used to drive \
asynchronous tasks."
);
}
/// Tries to enter a runtime context, returns `None` if already in a runtime
/// context.
pub(crate) fn try_enter() -> Option<Enter> {
ENTERED.with(|c| {
if c.get() {
Err(EnterError { _a: () })
None
} else {
c.set(true);
Ok(Enter { _p: PhantomData })
Some(Enter { _p: PhantomData })
}
})
}
+3 -4
View File
@@ -146,6 +146,8 @@ mod current_thread;
#[cfg(feature = "blocking")]
mod enter;
#[cfg(feature = "blocking")]
pub(crate) use self::enter::enter;
mod global;
pub use self::global::spawn;
@@ -340,10 +342,7 @@ impl Runtime {
let kind = &mut self.kind;
blocking::with_pool(&self.blocking_pool, || match kind {
Kind::Shell => {
let mut enter = enter::enter().unwrap();
enter.block_on(future)
}
Kind::Shell => enter().block_on(future),
#[cfg(feature = "rt-current-thread")]
Kind::CurrentThread(exec) => exec.block_on(future),
#[cfg(feature = "rt-full")]
+1 -2
View File
@@ -55,8 +55,7 @@ impl ThreadPool {
F: Future,
{
crate::runtime::global::with_thread_pool(self.spawner(), || {
let mut enter = crate::runtime::enter::enter()
.expect("attempting to block while on a Tokio executor");
let mut enter = crate::runtime::enter();
crate::runtime::blocking::with_pool(self.spawner.blocking_pool(), || {
enter.block_on(future)
})
+7 -10
View File
@@ -27,18 +27,15 @@ pub(super) fn channel() -> (Sender, Receiver) {
impl Receiver {
/// Block the current thread until all `Sender` handles drop.
pub(crate) fn wait(&mut self) {
use crate::runtime::enter::enter;
use crate::runtime::enter::{enter, try_enter};
let mut e = match enter() {
Ok(e) => e,
Err(_) => {
if std::thread::panicking() {
// Already panicking, avoid a double panic
return;
} else {
panic!("cannot block on shutdown from the Tokio runtime");
}
let mut e = if std::thread::panicking() {
match try_enter() {
Some(enter) => enter,
_ => return,
}
} else {
enter()
};
// The oneshot completes with an Err
+1 -2
View File
@@ -131,8 +131,7 @@ where
// Track the current worker
current::set(&pool, index, || {
let _enter =
crate::runtime::enter::enter().expect("executor already running on thread");
let _enter = crate::runtime::enter();
crate::runtime::global::with_thread_pool(&spawner, || {
crate::runtime::blocking::with_pool(blocking, || {