@@ -128,8 +128,58 @@ impl Reactor {
128128
129129 /// Block until at least one pending pollable is ready, waking a pending future.
130130 pub ( crate ) fn block_on_pollables ( & self ) {
131+ self . check_pollables ( |targets| {
132+ debug_assert_ne ! (
133+ targets. len( ) ,
134+ 0 ,
135+ "Attempting to block on an empty list of pollables - without any pending work, no progress can be made and wasi::io::poll::poll will trap"
136+ ) ;
137+ wasi:: io:: poll:: poll ( targets)
138+
139+ } )
140+ }
141+
142+ /// Without blocking, check for any ready pollables and wake the
143+ /// associated futures.
144+ pub ( crate ) fn nonblock_check_pollables ( & self ) {
145+ // Lazily create a pollable which always resolves to ready.
146+ use std:: sync:: LazyLock ;
147+ static READY_POLLABLE : LazyLock < Pollable > =
148+ LazyLock :: new ( || wasi:: clocks:: monotonic_clock:: subscribe_duration ( 0 ) ) ;
149+
150+ self . check_pollables ( |targets| {
151+ // Create a new set of targets, with the addition of the ready
152+ // pollable:
153+ let ready_index = targets. len ( ) ;
154+ let mut new_targets = Vec :: with_capacity ( ready_index + 1 ) ;
155+ new_targets. extend_from_slice ( targets) ;
156+ new_targets. push ( & * READY_POLLABLE ) ;
157+
158+ // Poll is now guaranteed to return immediately, because at least
159+ // one member is ready:
160+ let mut ready_list = wasi:: io:: poll:: poll ( & new_targets) ;
161+
162+ // Erase our extra ready pollable from the ready list:
163+ ready_list. retain ( |e| * e != ready_index as u32 ) ;
164+ ready_list
165+ } )
166+ }
167+
168+ /// Common core of blocking and nonblocking pollable checks. Wakes any
169+ /// futures which are pending on the pollables, according to the result of
170+ /// the check_ready function.
171+ fn check_pollables < F > ( & self , check_ready : F )
172+ where
173+ F : FnOnce ( & [ & Pollable ] ) -> Vec < u32 > ,
174+ {
131175 let reactor = self . inner . borrow ( ) ;
132176
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+
133183 // We're about to wait for a number of pollables. When they wake we get
134184 // the *indexes* back for the pollables whose events were available - so
135185 // we need to be able to associate the index with the right waker.
@@ -144,15 +194,9 @@ impl Reactor {
144194 targets. push ( & reactor. pollables [ pollable_index. 0 ] ) ;
145195 }
146196
147- debug_assert_ne ! (
148- targets. len( ) ,
149- 0 ,
150- "Attempting to block on an empty list of pollables - without any pending work, no progress can be made and wasi::io::poll::poll will trap"
151- ) ;
152-
153- // Now that we have that association, we're ready to poll our targets.
154- // This will block until an event has completed.
155- let ready_indexes = wasi:: io:: poll:: poll ( & targets) ;
197+ // Now that we have that association, we're ready to check our targets for readiness.
198+ // (This is either a wasi poll, or the nonblocking variant.)
199+ let ready_indexes = check_ready ( & targets) ;
156200
157201 // Once we have the indexes for which pollables are available, we need
158202 // to convert it back to the right keys for the wakers. Earlier we
0 commit comments