rt: fix spawn_blocking from spawn_blocking (#2006)

Nested spawn_blocking calls would result in a panic due to the necessary
context not being setup. This patch sets the blocking pool context from
within a blocking pool.

Fixes #1982
This commit is contained in:
Carl Lerche
2019-12-21 13:19:52 -08:00
committed by GitHub
parent 8656b7b8eb
commit 3d1b4b3058
2 changed files with 28 additions and 14 deletions
+13 -14
View File
@@ -244,32 +244,31 @@ impl Spawner {
builder = builder.stack_size(stack_size);
}
let inner = self.inner.clone();
let spawner = self.clone();
builder
.spawn(move || {
inner.run();
run_thread(spawner);
// Make sure `inner` drops first to ensure that the shutdown_rx
// sees all refs to `Inner` are dropped when the `shutdown_rx`
// resolves.
drop(inner);
drop(shutdown_tx);
})
.unwrap();
}
}
fn run_thread(spawner: Spawner) {
spawner.enter(|| {
let inner = &*spawner.inner;
let _io = io::set_default(&inner.io_handle);
time::with_default(&inner.time_handle, &inner.clock, || {
inner.spawner.enter(|| inner.run());
});
});
}
impl Inner {
fn run(&self) {
let _io = io::set_default(&self.io_handle);
time::with_default(&self.time_handle, &self.clock, || {
self.spawner.enter(|| self.run2());
});
}
fn run2(&self) {
if let Some(f) = &self.after_start {
f()
}
+15
View File
@@ -396,6 +396,21 @@ rt_test! {
assert_eq!(out, "hello")
}
#[test]
fn spawn_blocking_from_blocking() {
let mut rt = rt();
let out = rt.block_on(async move {
let inner = assert_ok!(tokio::task::spawn_blocking(|| {
tokio::task::spawn_blocking(|| "hello")
}).await);
assert_ok!(inner.await)
});
assert_eq!(out, "hello")
}
#[test]
fn delay_from_blocking() {
let mut rt = rt();