@@ -74,6 +74,18 @@ fn run_executor<T, F: FnMut(&mut Context<'_>) -> Poll<T>>(mut f: F) -> T {
7474 } )
7575}
7676
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+
7789impl LocalPool {
7890 /// Create a new, empty pool of tasks.
7991 pub fn new ( ) -> LocalPool {
@@ -135,8 +147,8 @@ impl LocalPool {
135147 /// The function will block the calling thread *only* until the future `f`
136148 /// completes; there may still be incomplete tasks in the pool, which will
137149 /// 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.
140152 pub fn run_until < F : Future > ( & mut self , future : F ) -> F :: Output {
141153 pin_mut ! ( future) ;
142154
@@ -154,20 +166,94 @@ impl LocalPool {
154166 } )
155167 }
156168
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+
157250 // Make maximal progress on the entire pool of spawned task, returning `Ready`
158251 // if the pool is empty and `Pending` if no further progress can be made.
159252 fn poll_pool ( & mut self , cx : & mut Context < ' _ > ) -> Poll < ( ) > {
160253 // state for the FuturesUnordered, which will never be used
161254 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) ;
169256
170- let ret = self . pool . poll_next_unpin ( cx) ;
171257 // we queued up some new tasks; add them and poll again
172258 if !self . incoming . borrow ( ) . is_empty ( ) {
173259 continue ;
@@ -181,6 +267,20 @@ impl LocalPool {
181267 }
182268 }
183269 }
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+ }
184284}
185285
186286impl Default for LocalPool {
0 commit comments