Skip to content

Conversation

pchickey
Copy link
Contributor

@pchickey pchickey commented Aug 8, 2025

Fixes #73.

Add test provided by @SilverMira in #70, tracked in #73.

Add a nonblock_check_pollables function to the reactor, for use in the "busy case" of the block_on loop. Factor out check_pollables, the common part of block_on_pollables and nonblock_check_pollables.

@pchickey pchickey assigned yoshuawuyts and unassigned yoshuawuyts Aug 8, 2025
@pchickey pchickey requested a review from yoshuawuyts August 8, 2025 20:21
Comment on lines +386 to +399
let mut future_group = futures_concurrency::future::FutureGroup::<
Pin<Box<dyn std::future::Future<Output = bool>>>,
>::new();
future_group.insert(Box::pin(cpu_heavy));
future_group.insert(Box::pin(timeout));
let result = futures_lite::StreamExt::next(&mut future_group).await;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm surprised this doesn't work here? Afaict this is just race-semantics?

Suggested change
let mut future_group = futures_concurrency::future::FutureGroup::<
Pin<Box<dyn std::future::Future<Output = bool>>>,
>::new();
future_group.insert(Box::pin(cpu_heavy));
future_group.insert(Box::pin(timeout));
let result = futures_lite::StreamExt::next(&mut future_group).await;
let result = (cpu_heavy, timeout).race().await;

Assuming futures_concurrency::prelude::*; is imported of course.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just tried this change, and it doesn't actually trigger the broken behavior that the existing test case does. I don't actually understand why, though.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's really weird; they should both work very similarly. The only real diffence I can think of is perhaps some amount of randomness in the execution order.

@SilverMira do you remember why you chose to use FutureGroup rather than Future::race?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@yoshuawuyts

do you remember why you chose to use FutureGroup rather than Future::race?

I only used it for as an repro, because in my actual project, the issue comes in the form of a deadlock, like how @teohhanhui experienced in #73 (comment).

The difference in between FutureGroup and Future::race lies in how it polls its inner futures, if I recall correctly, Future::race polls its inner futures in a random order whenever any one of its inner futures wake. Which means the wasi future could potentially be randomly chosen to be polled before the other task (even when it's not woken), and Pollable::ready would complete the future, thus winning the future.

Meanwhile, FutureGroup and others like StreamExt will explicitly skip un-woken inner futures when it itself is polled. Since the runtime isn't doing poll::poll while the main task is busy, it never wakes the wasi pollable, hence the FutureGroup never tries to poll them, causing it to lose the race.

pchickey and others added 3 commits August 11, 2025 11:52
as provided by @SilverMira in #70, and tracked in #73

Co-authored-by: SilverMira <[email protected]>
sharing most of the implementation with block_on_pollables
in the nonblocking case, we can skip work. in the blocking case, we need
to panic. In the absence of a panic, either the debug assert in
block_on_pollables will go off, or the wasi poll() will trap.
Copy link
Member

@yoshuawuyts yoshuawuyts left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good!

@yoshuawuyts yoshuawuyts merged commit 1cf72be into main Aug 14, 2025
4 checks passed
@pchickey pchickey deleted the pch/fix_73 branch August 14, 2025 16:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Futures should be woken before calling Future::poll
4 participants