diff --git a/crates/bevy_app/src/app.rs b/crates/bevy_app/src/app.rs index 097726a14399e..d852a3b063b63 100644 --- a/crates/bevy_app/src/app.rs +++ b/crates/bevy_app/src/app.rs @@ -8,10 +8,9 @@ use bevy_ecs::{ SystemStage, }, system::Resource, - world::World, }; -use bevy_tasks::ComputeTaskPool; +use bevy_tasks::{ComputeTaskPool, TaskPool}; use bevy_utils::{tracing::debug, HashMap, HashSet}; use std::fmt::Debug; @@ -154,7 +153,7 @@ impl App { pub fn update(&mut self) { #[cfg(feature = "trace")] let _bevy_frame_update_span = info_span!("frame").entered(); - ComputeTaskPool::get().scope(|scope| { + ComputeTaskPool::init(TaskPool::default).scope(|scope| { if self.run_once { for sub_app in self.sub_apps.values_mut() { (sub_app.extract)(&mut self.world, &mut sub_app.app); diff --git a/crates/bevy_tasks/src/main_thread_executor.rs b/crates/bevy_tasks/src/main_thread_executor.rs index b90a8abe03ea9..8fc2acc7f9f87 100644 --- a/crates/bevy_tasks/src/main_thread_executor.rs +++ b/crates/bevy_tasks/src/main_thread_executor.rs @@ -10,7 +10,10 @@ static MAIN_THREAD_EXECUTOR: OnceCell = OnceCell::new(); /// Use to access the global main thread executor. Be aware that the main thread executor /// only makes progress when it is ticked. This normally happens in `[TaskPool::scope]`. #[derive(Debug)] -pub struct MainThreadExecutor(Arc>); +pub struct MainThreadExecutor( + // this is only pub crate for testing purposes, do not contruct otherwise + pub(crate) Arc>, +); impl MainThreadExecutor { /// Initializes the global `[MainThreadExecutor]` instance. @@ -39,6 +42,17 @@ impl MainThreadExecutor { /// Use this to tick the main thread executor. /// Returns None if called on not the main thread. pub fn ticker(&self) -> Option { + // always return ticker when testing to allow tests to run off main thread + dbg!("hjj"); + #[cfg(test)] + if true { + dbg!("blah"); + return Some(MainThreadTicker { + executor: self.0.clone(), + _marker: PhantomData::default(), + }); + } + if let Some(is_main) = is_main_thread() { if is_main { return Some(MainThreadTicker { @@ -69,7 +83,7 @@ pub struct MainThreadTicker { impl MainThreadTicker { /// Tick the main thread executor. /// This needs to be called manually on the main thread if a `[TaskPool::scope]` is not active - pub fn tick<'a>(&'a self) -> impl Future + 'a { + pub fn tick(&self) -> impl Future + '_ { self.executor.tick() } } diff --git a/crates/bevy_tasks/src/task_pool.rs b/crates/bevy_tasks/src/task_pool.rs index dde21334ff3a3..9102b34280b42 100644 --- a/crates/bevy_tasks/src/task_pool.rs +++ b/crates/bevy_tasks/src/task_pool.rs @@ -245,7 +245,15 @@ impl TaskPool { // transmute the lifetimes to 'env here to appease the compiler as it is unable to validate safety. let executor: &async_executor::Executor = &self.executor; let executor: &'env async_executor::Executor = unsafe { mem::transmute(executor) }; - let main_thread_spawner = MainThreadExecutor::init().spawner(); + + #[cfg(not(test))] + let main_thread_executor = MainThreadExecutor::init(); + // for testing configure a new instance of main thread executor for every scope + // this helps us pretend that the thread that an app or stage is constructed on is the main thread + #[cfg(test)] + let main_thread_executor = MainThreadExecutor(Arc::new(async_executor::Executor::new())); + + let main_thread_spawner = main_thread_executor.spawner(); let main_thread_spawner: MainThreadSpawner<'env> = unsafe { mem::transmute(main_thread_spawner) }; let spawned: ConcurrentQueue> = ConcurrentQueue::unbounded(); @@ -277,9 +285,10 @@ impl TaskPool { results }; - if let Some(main_thread_ticker) = MainThreadExecutor::get().ticker() { + if let Some(main_thread_ticker) = main_thread_executor.ticker() { let tick_forever = async move { loop { + dbg!("tivk"); main_thread_ticker.tick().await; } }; @@ -441,7 +450,7 @@ mod tests { } #[test] - fn test_mixed_spawn_on_scope_and_spawn() { + fn test_mixed_spawn_on_main_and_spawn() { let pool = TaskPool::new(); let foo = Box::new(42);