@@ -128,8 +128,58 @@ impl Reactor {
128
128
129
129
/// Block until at least one pending pollable is ready, waking a pending future.
130
130
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
+ {
131
175
let reactor = self . inner . borrow ( ) ;
132
176
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
+
133
183
// We're about to wait for a number of pollables. When they wake we get
134
184
// the *indexes* back for the pollables whose events were available - so
135
185
// we need to be able to associate the index with the right waker.
@@ -144,15 +194,9 @@ impl Reactor {
144
194
targets. push ( & reactor. pollables [ pollable_index. 0 ] ) ;
145
195
}
146
196
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) ;
156
200
157
201
// Once we have the indexes for which pollables are available, we need
158
202
// to convert it back to the right keys for the wakers. Earlier we
0 commit comments