Skip to content

Commit 18d97a2

Browse files
committed
factor out check for nonempty pending 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.
1 parent 83667be commit 18d97a2

File tree

2 files changed

+22
-6
lines changed

2 files changed

+22
-6
lines changed

src/runtime/block_on.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,14 @@ where
4040
reactor.nonblock_check_pollables();
4141
root.reset()
4242
} else {
43+
// If there are no futures awake or waiting on a WASI
44+
// pollable, its impossible for the reactor to make
45+
// progress, and the only valid behaviors are to sleep
46+
// forever or panic. This should only be reachable if the
47+
// user's Futures are implemented incorrectly.
48+
if !reactor.nonempty_pending_pollables() {
49+
panic!("reactor has no futures which are awake, or are waiting on a WASI pollable to be ready")
50+
}
4351
reactor.block_on_pollables()
4452
}
4553
}

src/runtime/reactor.rs

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,15 @@ impl Reactor {
126126
}
127127
}
128128

129+
/// The reactor tracks the set of WASI pollables which have an associated
130+
/// Future pending on their readiness. This function returns indicating
131+
/// that set of pollables is not empty.
132+
pub(crate) fn nonempty_pending_pollables(&self) -> bool {
133+
!self.inner.borrow().wakers.is_empty()
134+
}
135+
129136
/// Block until at least one pending pollable is ready, waking a pending future.
137+
/// Precondition: self.nonempty_pending_pollables() is true.
130138
pub(crate) fn block_on_pollables(&self) {
131139
self.check_pollables(|targets| {
132140
debug_assert_ne!(
@@ -142,6 +150,11 @@ impl Reactor {
142150
/// Without blocking, check for any ready pollables and wake the
143151
/// associated futures.
144152
pub(crate) fn nonblock_check_pollables(&self) {
153+
// If there are no pollables with associated pending futures, there is
154+
// no work to do here, so return immediately.
155+
if !self.nonempty_pending_pollables() {
156+
return;
157+
}
145158
// Lazily create a pollable which always resolves to ready.
146159
use std::sync::LazyLock;
147160
static READY_POLLABLE: LazyLock<Pollable> =
@@ -168,18 +181,13 @@ impl Reactor {
168181
/// Common core of blocking and nonblocking pollable checks. Wakes any
169182
/// futures which are pending on the pollables, according to the result of
170183
/// the check_ready function.
184+
/// Precondition: self.nonempty_pending_pollables() is true.
171185
fn check_pollables<F>(&self, check_ready: F)
172186
where
173187
F: FnOnce(&[&Pollable]) -> Vec<u32>,
174188
{
175189
let reactor = self.inner.borrow();
176190

177-
// If no wakers are pending on pollables, there is no work to be done
178-
// here:
179-
if reactor.wakers.is_empty() {
180-
return;
181-
}
182-
183191
// We're about to wait for a number of pollables. When they wake we get
184192
// the *indexes* back for the pollables whose events were available - so
185193
// we need to be able to associate the index with the right waker.

0 commit comments

Comments
 (0)