@@ -3,11 +3,11 @@ use std::{
3
3
marker:: PhantomData ,
4
4
mem,
5
5
sync:: Arc ,
6
- thread:: { self , JoinHandle } ,
6
+ thread:: { self , JoinHandle } , pin :: Pin ,
7
7
} ;
8
8
9
9
use concurrent_queue:: ConcurrentQueue ;
10
- use futures_lite:: { future, FutureExt } ;
10
+ use futures_lite:: { future, pin } ;
11
11
12
12
use crate :: Task ;
13
13
@@ -241,7 +241,9 @@ impl TaskPool {
241
241
242
242
f ( scope_ref) ;
243
243
244
- future:: block_on ( async move {
244
+ if spawned. is_empty ( ) {
245
+ Vec :: new ( )
246
+ } else {
245
247
let get_results = async move {
246
248
let mut results = Vec :: with_capacity ( spawned. len ( ) ) ;
247
249
while let Ok ( task) = spawned. pop ( ) {
@@ -251,17 +253,33 @@ impl TaskPool {
251
253
results
252
254
} ;
253
255
254
- let tick_forever = async move {
255
- loop {
256
- self . executor . try_tick ( ) ;
257
- task_scope_executor. try_tick ( ) ;
258
-
259
- future:: yield_now ( ) . await ;
260
- }
261
- } ;
262
-
263
- get_results. or ( tick_forever) . await
264
- } )
256
+ // Pin the futures on the stack.
257
+ pin ! ( get_results) ;
258
+
259
+ // SAFETY: This function blocks until all futures complete, so we do not read/write
260
+ // the data from futures outside of the 'scope lifetime. However,
261
+ // rust has no way of knowing this so we must convert to 'static
262
+ // here to appease the compiler as it is unable to validate safety.
263
+ let get_results: Pin < & mut ( dyn Future < Output = Vec < T > > + ' static + Send ) > = get_results;
264
+ let get_results: Pin < & ' static mut ( dyn Future < Output = Vec < T > > + ' static + Send ) > =
265
+ unsafe { mem:: transmute ( get_results) } ;
266
+
267
+ // The thread that calls scope() will participate in driving tasks in the pool
268
+ // forward until the tasks that are spawned by this scope() call
269
+ // complete. (If the caller of scope() happens to be a thread in
270
+ // this thread pool, and we only have one thread in the pool, then
271
+ // simply calling future::block_on(spawned) would deadlock.)
272
+ let mut spawned = task_scope_executor. spawn ( get_results) ;
273
+
274
+ loop {
275
+ if let Some ( result) = future:: block_on ( future:: poll_once ( & mut spawned) ) {
276
+ break result;
277
+ } ;
278
+
279
+ self . executor . try_tick ( ) ;
280
+ task_scope_executor. try_tick ( ) ;
281
+ }
282
+ }
265
283
}
266
284
267
285
/// Spawns a static future onto the thread pool. The returned Task is a future. It can also be
0 commit comments