Skip to content

Commit addbfb9

Browse files
authored
rt: skip defer queue in block_in_place context (#7216)
1 parent 8182ecf commit addbfb9

File tree

3 files changed

+63
-1
lines changed

3 files changed

+63
-1
lines changed

tokio/src/runtime/scheduler/multi_thread/worker.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -782,7 +782,13 @@ impl Context {
782782
}
783783

784784
pub(crate) fn defer(&self, waker: &Waker) {
785-
self.defer.defer(waker);
785+
if self.core.borrow().is_none() {
786+
// If there is no core, then the worker is currently in a block_in_place. In this case,
787+
// we cannot use the defer queue as we aren't really in the current runtime.
788+
waker.wake_by_ref();
789+
} else {
790+
self.defer.defer(waker);
791+
}
786792
}
787793

788794
#[allow(dead_code)]

tokio/tests/rt_handle_block_on.rs

+11
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,17 @@ fn unbounded_mpsc_channel() {
126126
})
127127
}
128128

129+
#[test]
130+
fn yield_in_block_in_place() {
131+
test_with_runtimes(|| {
132+
Handle::current().block_on(async {
133+
tokio::task::block_in_place(|| {
134+
Handle::current().block_on(tokio::task::yield_now());
135+
});
136+
});
137+
})
138+
}
139+
129140
#[cfg(not(target_os = "wasi"))] // Wasi doesn't support file operations or bind
130141
rt_test! {
131142
use tokio::fs;

tokio/tests/rt_threaded.rs

+45
Original file line numberDiff line numberDiff line change
@@ -647,6 +647,51 @@ fn test_nested_block_in_place_with_block_on_between() {
647647
}
648648
}
649649

650+
#[test]
651+
fn yield_now_in_block_in_place() {
652+
let rt = runtime::Builder::new_multi_thread()
653+
.worker_threads(1)
654+
.build()
655+
.unwrap();
656+
657+
rt.block_on(async {
658+
tokio::spawn(async {
659+
tokio::task::block_in_place(|| {
660+
tokio::runtime::Handle::current().block_on(tokio::task::yield_now());
661+
})
662+
})
663+
.await
664+
.unwrap()
665+
})
666+
}
667+
668+
#[test]
669+
fn mutex_in_block_in_place() {
670+
const BUDGET: usize = 128;
671+
672+
let rt = runtime::Builder::new_multi_thread()
673+
.worker_threads(1)
674+
.build()
675+
.unwrap();
676+
677+
rt.block_on(async {
678+
let lock = tokio::sync::Mutex::new(0);
679+
680+
tokio::spawn(async move {
681+
tokio::task::block_in_place(|| {
682+
tokio::runtime::Handle::current().block_on(async move {
683+
for i in 0..(BUDGET + 1) {
684+
let mut guard = lock.lock().await;
685+
*guard = i;
686+
}
687+
});
688+
})
689+
})
690+
.await
691+
.unwrap();
692+
})
693+
}
694+
650695
// Testing the tuning logic is tricky as it is inherently timing based, and more
651696
// of a heuristic than an exact behavior. This test checks that the interval
652697
// changes over time based on load factors. There are no assertions, completion

0 commit comments

Comments
 (0)