Skip to content

external executor block_on and yield defer do not work together #6996

@quininer

Description

@quininer

Version

└── tokio v1.41.1
    └── tokio-macros v2.4.0 (proc-macro)

Platform

Linux hay 6.11.8-arch1-2 #1 SMP PREEMPT_DYNAMIC Fri, 15 Nov 2024 15:35:07 +0000 x86_64 GNU/Linux

Description

when yield_now().await is called in an external executor block_on, the wakeup maybe lost due to enter defer logic.

I tried this code:

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=c12f5f957e5a1d33c4184d52b07e40b5

use std::sync::LazyLock;
use tokio::runtime;

const GLOBAL: LazyLock<runtime::Runtime> = LazyLock::new(|| {
    runtime::Builder::new_multi_thread().build().unwrap()
});

async fn task() {
    println!("start");
    tokio::task::yield_now().await;
    println!("done");
}

fn yield_no_back() {
    let j = GLOBAL.spawn(async {
        futures_executor::block_on(task());
    });
    GLOBAL.block_on(j).unwrap();
}

fn main() {
    yield_no_back();
}

I also tried block_on with block_in_place, but this still results in lost wakeups because block_in_place only exits runtime but not scheduler.

https://github.com/tokio-rs/tokio/blob/tokio-1.41.1/tokio/src/runtime/context/runtime_mt.rs#L29
https://github.com/tokio-rs/tokio/blob/tokio-1.41.1/tokio/src/runtime/context.rs#L184

I expected to see this happen: print start and done.

Instead, this happened: prints start and then hangs.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-tokioArea: The main tokio crateC-bugCategory: This is a bug.M-blockingModule: tokio/task/blockingM-runtimeModule: tokio/runtimeM-taskModule: tokio/task

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions