Skip to content

Commit 710bc80

Browse files
authored
rt: coop should yield using waker defer strategy (#7185)
1 parent a2b12bd commit 710bc80

File tree

2 files changed

+40
-4
lines changed

2 files changed

+40
-4
lines changed

tokio/src/task/coop/mod.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,7 @@ cfg_coop! {
305305

306306
Poll::Ready(restore)
307307
} else {
308-
cx.waker().wake_by_ref();
308+
defer(cx);
309309
Poll::Pending
310310
}
311311
}).unwrap_or(Poll::Ready(RestoreOnPending(Cell::new(Budget::unconstrained()))))
@@ -325,11 +325,19 @@ cfg_coop! {
325325
#[inline(always)]
326326
fn inc_budget_forced_yield_count() {}
327327
}
328+
329+
fn defer(cx: &mut Context<'_>) {
330+
context::defer(cx.waker());
331+
}
328332
}
329333

330334
cfg_not_rt! {
331335
#[inline(always)]
332336
fn inc_budget_forced_yield_count() {}
337+
338+
fn defer(cx: &mut Context<'_>) {
339+
cx.waker().wake_by_ref();
340+
}
333341
}
334342

335343
impl Budget {

tokio/tests/rt_common.rs

+31-3
Original file line numberDiff line numberDiff line change
@@ -745,7 +745,25 @@ rt_test! {
745745
#[cfg_attr(miri, ignore)] // No `socket` in miri.
746746
fn yield_defers_until_park() {
747747
for _ in 0..10 {
748-
if yield_defers_until_park_inner() {
748+
if yield_defers_until_park_inner(false) {
749+
// test passed
750+
return;
751+
}
752+
753+
// Wait a bit and run the test again.
754+
std::thread::sleep(std::time::Duration::from_secs(2));
755+
}
756+
757+
panic!("yield_defers_until_park is failing consistently");
758+
}
759+
760+
/// Same as above, but with cooperative scheduling.
761+
#[test]
762+
#[cfg(not(target_os="wasi"))]
763+
#[cfg_attr(miri, ignore)] // No `socket` in miri.
764+
fn coop_yield_defers_until_park() {
765+
for _ in 0..10 {
766+
if yield_defers_until_park_inner(true) {
749767
// test passed
750768
return;
751769
}
@@ -760,10 +778,12 @@ rt_test! {
760778
/// Implementation of `yield_defers_until_park` test. Returns `true` if the
761779
/// test passed.
762780
#[cfg(not(target_os="wasi"))]
763-
fn yield_defers_until_park_inner() -> bool {
781+
fn yield_defers_until_park_inner(use_coop: bool) -> bool {
764782
use std::sync::atomic::{AtomicBool, Ordering::SeqCst};
765783
use std::sync::Barrier;
766784

785+
const BUDGET: usize = 128;
786+
767787
let rt = rt();
768788

769789
let flag = Arc::new(AtomicBool::new(false));
@@ -802,7 +822,15 @@ rt_test! {
802822
// Yield until connected
803823
let mut cnt = 0;
804824
while !flag_clone.load(SeqCst){
805-
tokio::task::yield_now().await;
825+
if use_coop {
826+
// Consume a good chunk of budget, which should
827+
// force at least one yield.
828+
for _ in 0..BUDGET {
829+
tokio::task::consume_budget().await;
830+
}
831+
} else {
832+
tokio::task::yield_now().await;
833+
}
806834
cnt += 1;
807835

808836
if cnt >= 10 {

0 commit comments

Comments
 (0)