-
Notifications
You must be signed in to change notification settings - Fork 628
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Shared combinator can block the executor #2130
Comments
Interesting, this is sort of the exact opposite of #2047, it's a bug triggered by wrapping a future that is never ready (or cannot become ready while the current thread is blocked), but still immediately requests a wakeup when polled. (EDIT: Ah, reading further in #2047 this same issue is brought up in the context of As a quick testcase (playground) let mut fut = poll_fn::<(), _>(|ctx| {
ctx.waker().wake_by_ref();
Poll::Pending
})
.shared();
let mut ctx = Context::from_waker(noop_waker_ref());
assert_eq!(fut.poll_unpin(&mut ctx), Poll::Pending); Maybe the |
If I understand the implementation correctly, it would be correct to simply return Would love to hear from someone familiar with the implementation though. |
Depending on what exact expectations is here between executors and wakers this might be better fixed on tokio's side. What tokio does here is to tell the executor that this task should be woken immediately which works ok as long as it is tokio's executor that gets woken directly. However here So an alternative "fix" could be to alter tokio's pub fn poll_proceed(cx: &mut Context<'_>) -> Poll<()> {
HITS.with(|hits| {
let n = hits.get();
if n == UNCONSTRAINED {
// opted out of budgeting
Poll::Ready(())
} else if n == 1 { // Need to adjust the BUDGET + 1 also
cx.waker().wake_by_ref();
Poll::Pending
} else if n == 0 {
Poll::Pending
} else {
hits.set(n.saturating_sub(1));
Poll::Ready(())
}
})
} |
If the wrapped future requires that another future runs before it stops waking itself while returning pending the current Shared will loop forever. This removes the `REPOLL` case and returns pending immediately, since the current task is recorded and therefore woken through `Notifier`'s `wake_by_ref` the `Shared` future will still be polled again Fixes rust-lang#2130
If the wrapped future requires that another future runs before it stops waking itself while returning pending the current Shared will loop forever. This removes the `REPOLL` case and returns pending immediately, since the current task is recorded and therefore woken through `Notifier`'s `wake_by_ref` the `Shared` future will still be polled again Fixes #2130
If the wrapped future requires that another future runs before it stops waking itself while returning pending the current Shared will loop forever. This removes the `REPOLL` case and returns pending immediately, since the current task is recorded and therefore woken through `Notifier`'s `wake_by_ref` the `Shared` future will still be polled again Fixes rust-lang#2130
In a similar vein to #2047, the
FutureExt::shared
combinator can block the executor by repeatedly polling the future in an infinite loop. Originally discovered in tokio#2418.The issue is the
REPOLL
case in the match below, which unconditionally polls the future again without yielding.futures-rs/futures-util/src/future/future/shared.rs
Lines 232 to 262 in 6ba6716
The text was updated successfully, but these errors were encountered: