@@ -74,6 +74,18 @@ fn run_executor<T, F: FnMut(&mut Context<'_>) -> Poll<T>>(mut f: F) -> T {
74
74
} )
75
75
}
76
76
77
+ fn poll_executor < T , F : FnMut ( & mut Context < ' _ > ) -> T > ( mut f : F ) -> T {
78
+ let _enter = enter ( )
79
+ . expect ( "cannot execute `LocalPool` executor from within \
80
+ another executor") ;
81
+
82
+ CURRENT_THREAD_NOTIFY . with ( |thread_notify| {
83
+ let waker = waker_ref ( thread_notify) ;
84
+ let mut cx = Context :: from_waker ( & waker) ;
85
+ f ( & mut cx)
86
+ } )
87
+ }
88
+
77
89
impl LocalPool {
78
90
/// Create a new, empty pool of tasks.
79
91
pub fn new ( ) -> LocalPool {
@@ -135,8 +147,8 @@ impl LocalPool {
135
147
/// The function will block the calling thread *only* until the future `f`
136
148
/// completes; there may still be incomplete tasks in the pool, which will
137
149
/// be inert after the call completes, but can continue with further use of
138
- /// ` run` or `run_until` . While the function is running, however, all tasks
139
- /// in the pool will try to make progress.
150
+ /// one of the pool's run or poll mothods . While the function is running,
151
+ /// however, all tasks in the pool will try to make progress.
140
152
pub fn run_until < F : Future > ( & mut self , future : F ) -> F :: Output {
141
153
pin_mut ! ( future) ;
142
154
@@ -154,20 +166,94 @@ impl LocalPool {
154
166
} )
155
167
}
156
168
169
+ /// Runs all tasks and returns after completing one future or until no more progress
170
+ /// can be made. Returns `true` if one future was completed, `false` otherwise.
171
+ ///
172
+ /// ```
173
+ /// #![feature(futures_api)]
174
+ /// use futures::executor::LocalPool;
175
+ /// use futures::task::LocalSpawnExt;
176
+ /// use futures::future::{ready, empty};
177
+ ///
178
+ /// let mut pool = LocalPool::new();
179
+ /// let mut spawner = pool.spawner();
180
+ ///
181
+ /// spawner.spawn_local(ready(()));
182
+ /// spawner.spawn_local(ready(()));
183
+ /// spawner.spawn_local(empty());
184
+ ///
185
+ /// // Run the two ready tasks and return true for them.
186
+ /// pool.poll_one(); // returns true after completing one of the ready futures
187
+ /// pool.poll_one(); // returns true after completing the other ready future
188
+ ///
189
+ /// // the remaining task can not be completed
190
+ /// pool.poll_one(); // returns false
191
+ /// ```
192
+ ///
193
+ /// This function will not block the calling thread and will return the moment
194
+ /// that there are no tasks left for which progress can be made or after exactly one
195
+ /// task was completed; Remaining incomplete tasks in the pool can continue with
196
+ /// further use of one of the pool's run or poll methods.
197
+ /// Though only one task will be completed, progress may be made on multiple tasks.
198
+ pub fn poll_one ( & mut self ) -> bool {
199
+ poll_executor ( |ctx| {
200
+ let ret = self . poll_pool_once ( ctx) ;
201
+
202
+ // return if we really have executed a future
203
+ match ret {
204
+ Poll :: Ready ( Some ( _) ) => true ,
205
+ _ => false
206
+ }
207
+ } )
208
+ }
209
+
210
+ /// Runs all tasks in the pool and returns if no more progress can be made
211
+ /// on any task.
212
+ ///
213
+ /// ```
214
+ /// #![feature(futures_api)]
215
+ /// use futures::executor::LocalPool;
216
+ /// use futures::task::LocalSpawnExt;
217
+ /// use futures::future::{ready, empty};
218
+ ///
219
+ /// let mut pool = LocalPool::new();
220
+ /// let mut spawner = pool.spawner();
221
+ ///
222
+ /// spawner.spawn_local(ready(()));
223
+ /// spawner.spawn_local(ready(()));
224
+ /// spawner.spawn_local(empty());
225
+ ///
226
+ /// // Runs the two ready task and returns.
227
+ /// // The empty task remains in the pool.
228
+ /// pool.poll();
229
+ /// ```
230
+ ///
231
+ /// This function will not block the calling thread and will return the moment
232
+ /// that there are no tasks left for which progress can be made;
233
+ /// remaining incomplete tasks in the pool can continue with further use of one
234
+ /// of the pool's run or poll methods. While the function is running, all tasks
235
+ /// in the pool will try to make progress.
236
+ pub fn poll ( & mut self ) {
237
+ poll_executor ( |ctx| {
238
+ loop {
239
+ let result = self . poll_pool_once ( ctx) ;
240
+
241
+ // if there are no more ready futures exit
242
+ match result {
243
+ Poll :: Pending | Poll :: Ready ( None ) => return ,
244
+ _ => continue
245
+ }
246
+ }
247
+ } )
248
+ }
249
+
157
250
// Make maximal progress on the entire pool of spawned task, returning `Ready`
158
251
// if the pool is empty and `Pending` if no further progress can be made.
159
252
fn poll_pool ( & mut self , cx : & mut Context < ' _ > ) -> Poll < ( ) > {
160
253
// state for the FuturesUnordered, which will never be used
161
254
loop {
162
- // empty the incoming queue of newly-spawned tasks
163
- {
164
- let mut incoming = self . incoming . borrow_mut ( ) ;
165
- for task in incoming. drain ( ..) {
166
- self . pool . push ( task)
167
- }
168
- }
255
+ let ret = self . poll_pool_once ( cx) ;
169
256
170
- let ret = self . pool . poll_next_unpin ( cx) ;
171
257
// we queued up some new tasks; add them and poll again
172
258
if !self . incoming . borrow ( ) . is_empty ( ) {
173
259
continue ;
@@ -181,6 +267,20 @@ impl LocalPool {
181
267
}
182
268
}
183
269
}
270
+
271
+ // Try make minimal progress on the pool of spawned tasks
272
+ fn poll_pool_once ( & mut self , cx : & mut Context < ' _ > ) -> Poll < Option < ( ) > > {
273
+ // empty the incoming queue of newly-spawned tasks
274
+ {
275
+ let mut incoming = self . incoming . borrow_mut ( ) ;
276
+ for task in incoming. drain ( ..) {
277
+ self . pool . push ( task)
278
+ }
279
+ }
280
+
281
+ // try to execute the next ready future
282
+ self . pool . poll_next_unpin ( cx)
283
+ }
184
284
}
185
285
186
286
impl Default for LocalPool {
0 commit comments