Skip to content

Commit 9103c8c

Browse files
committed
runtime: don't sleep in current_thread if before_park populated deferred queue
This ensures that if a before_park hook calls yield_now(), the runtime doesn't enter a blocking sleep, which would delay or deadlock the deferred task.
1 parent 41d1877 commit 9103c8c

1 file changed

Lines changed: 40 additions & 0 deletions

File tree

tokio/tests/rt_basic.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -456,3 +456,43 @@ fn rt() -> Runtime {
456456
.build()
457457
.unwrap()
458458
}
459+
460+
#[test]
461+
fn before_park_yields() {
462+
use futures::task::ArcWake;
463+
use std::sync::Arc;
464+
use tokio::runtime::Builder;
465+
use tokio::sync::Notify;
466+
467+
struct MyWaker(Notify);
468+
469+
impl ArcWake for MyWaker {
470+
fn wake_by_ref(arc_self: &Arc<Self>) {
471+
arc_self.0.notify_one();
472+
}
473+
}
474+
475+
let notify = Arc::new(MyWaker(Notify::new()));
476+
let notify2 = notify.clone();
477+
let waker = futures::task::waker(notify2);
478+
let woken = Arc::new(AtomicBool::new(false));
479+
let woken2 = woken.clone();
480+
481+
let rt = Builder::new_current_thread()
482+
.enable_all()
483+
.on_thread_park(move || {
484+
if !woken2.swap(true, Ordering::SeqCst) {
485+
let mut cx = Context::from_waker(&waker);
486+
let mut fut = std::pin::pin!(tokio::task::yield_now());
487+
let _ = Pin::new(&mut fut).poll(&mut cx);
488+
}
489+
})
490+
.build()
491+
.unwrap();
492+
493+
rt.block_on(async {
494+
notify.0.notified().await;
495+
});
496+
497+
assert!(woken.load(Ordering::SeqCst));
498+
}

0 commit comments

Comments
 (0)