diff --git a/crates/bevy_tasks/src/task_pool.rs b/crates/bevy_tasks/src/task_pool.rs index 1a8a2d723ddddd..490ba83bd9d30c 100644 --- a/crates/bevy_tasks/src/task_pool.rs +++ b/crates/bevy_tasks/src/task_pool.rs @@ -3,7 +3,7 @@ use std::{ marker::PhantomData, mem, sync::Arc, - thread::{self, JoinHandle}, + thread::{self, JoinHandle}, pin::Pin, }; use async_task::FallibleTask; @@ -279,8 +279,23 @@ impl TaskPool { // Pin the futures on the stack. pin!(get_results); + // SAFETY: This function blocks until all futures complete, so we do not read/write + // the data from futures outside of the 'scope lifetime. However, + // rust has no way of knowing this so we must convert to 'static + // here to appease the compiler as it is unable to validate safety. + let get_results: Pin<&mut (dyn Future> + 'static + Send)> = get_results; + let get_results: Pin<&'static mut (dyn Future> + 'static + Send)> = + unsafe { mem::transmute(get_results) }; + + // The thread that calls scope() will participate in driving tasks in the pool + // forward until the tasks that are spawned by this scope() call + // complete. (If the caller of scope() happens to be a thread in + // this thread pool, and we only have one thread in the pool, then + // simply calling future::block_on(spawned) would deadlock.) + let mut spawned = task_scope_executor.spawn(get_results); + loop { - if let Some(result) = future::block_on(future::poll_once(&mut get_results)) { + if let Some(result) = future::block_on(future::poll_once(&mut spawned)) { break result; };