summaryrefslogtreecommitdiffstats
path: root/tokio/src/runtime/thread_pool
diff options
context:
space:
mode:
authorJon Gjengset <jon@thesquareplanet.com>2020-04-20 19:18:47 -0400
committerGitHub <noreply@github.com>2020-04-20 19:18:47 -0400
commit282b00cbe888a96669877ce70662fba87e8c0e3c (patch)
tree49482c1ffc2862e8154fe81aec5a3c24eac8ba5a /tokio/src/runtime/thread_pool
parent5a548044d7bfd5d1c59d1a398d34ccbc29cbfe70 (diff)
Be more principled about when blocking is ok (#2410)
This enables `block_in_place` to be used in more contexts. Specifically, it allows you to block whenever you are off the tokio runtime (like if you are not using tokio, are in a `spawn_blocking` closure, etc.), and in the threaded scheduler's `block_on`. Blocking in `LocalSet` and the basic scheduler's` block_on` is still disallowed. Fixes #2327. Fixes #2393.
Diffstat (limited to 'tokio/src/runtime/thread_pool')
-rw-r--r--tokio/src/runtime/thread_pool/mod.rs2
-rw-r--r--tokio/src/runtime/thread_pool/worker.rs32
2 files changed, 31 insertions, 3 deletions
diff --git a/tokio/src/runtime/thread_pool/mod.rs b/tokio/src/runtime/thread_pool/mod.rs
index 82e82d5b..ced9712d 100644
--- a/tokio/src/runtime/thread_pool/mod.rs
+++ b/tokio/src/runtime/thread_pool/mod.rs
@@ -78,7 +78,7 @@ impl ThreadPool {
where
F: Future,
{
- let mut enter = crate::runtime::enter();
+ let mut enter = crate::runtime::enter(true);
enter.block_on(future).expect("failed to park thread")
}
}
diff --git a/tokio/src/runtime/thread_pool/worker.rs b/tokio/src/runtime/thread_pool/worker.rs
index 2213ec6c..e31f237c 100644
--- a/tokio/src/runtime/thread_pool/worker.rs
+++ b/tokio/src/runtime/thread_pool/worker.rs
@@ -172,6 +172,8 @@ pub(super) fn create(size: usize, park: Parker) -> (Arc<Shared>, Launch) {
}
cfg_blocking! {
+ use crate::runtime::enter::EnterContext;
+
pub(crate) fn block_in_place<F, R>(f: F) -> R
where
F: FnOnce() -> R,
@@ -203,7 +205,33 @@ cfg_blocking! {
let mut had_core = false;
CURRENT.with(|maybe_cx| {
- let cx = maybe_cx.expect("can call blocking only when running in a spawned task on the multi-threaded runtime");
+ match (crate::runtime::enter::context(), maybe_cx.is_some()) {
+ (EnterContext::Entered { .. }, true) => {
+ // We are on a thread pool runtime thread, so we just need to set up blocking.
+ }
+ (EnterContext::Entered { allow_blocking }, false) => {
+ // We are on an executor, but _not_ on the thread pool.
+ // That is _only_ okay if we are in a thread pool runtime's block_on method:
+ if allow_blocking {
+ return;
+ } else {
+ // This probably means we are on the basic_scheduler or in a LocalSet,
+ // where it is _not_ okay to block.
+ panic!("can call blocking only when running on the multi-threaded runtime");
+ }
+ }
+ (EnterContext::NotEntered, true) => {
+ // This is a nested call to block_in_place (we already exited).
+ // All the necessary setup has already been done.
+ return;
+ }
+ (EnterContext::NotEntered, false) => {
+ // We are outside of the tokio runtime, so blocking is fine.
+ // We can also skip all of the thread pool blocking setup steps.
+ return;
+ }
+ }
+ let cx = maybe_cx.expect("no .is_some() == false cases above should lead here");
// Get the worker core. If none is set, then blocking is fine!
let core = match cx.core.borrow_mut().take() {
@@ -273,7 +301,7 @@ fn run(worker: Arc<Worker>) {
core: RefCell::new(None),
};
- let _enter = crate::runtime::enter();
+ let _enter = crate::runtime::enter(true);
CURRENT.set(&cx, || {
// This should always be an error. It only returns a `Result` to support