From 27e20df6de69606ff3de69786a6c61b82fb10e4a Mon Sep 17 00:00:00 2001 From: Mike Date: Fri, 3 Feb 2023 02:35:20 +0000 Subject: [PATCH] Stageless: move final apply outside of spawned executor (#7445) # Objective - After the multithreaded executor finishes running all the systems, we apply the buffers for any system that hasn't applied it's buffers. This is a courtesy apply for users who forget to order their systems before a apply_system_buffers. When checking stageless, it was found that this apply_system_buffers was running on the executor thread instead of the world's thread. This is a problem because anything with world access should be able to access nonsend resources. ## Solution - Move the final apply_system_buffers outside of the executor and outside of the scope, so it runs on the same thread that schedule.run is called on. --- .../schedule_v3/executor/multi_threaded.rs | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/crates/bevy_ecs/src/schedule_v3/executor/multi_threaded.rs b/crates/bevy_ecs/src/schedule_v3/executor/multi_threaded.rs index ab1357e510f07..21d6c5d4cdb7f 100644 --- a/crates/bevy_ecs/src/schedule_v3/executor/multi_threaded.rs +++ b/crates/bevy_ecs/src/schedule_v3/executor/multi_threaded.rs @@ -178,19 +178,6 @@ impl SystemExecutor for MultiThreadedExecutor { self.rebuild_active_access(); } } - - // SAFETY: all systems have completed - let world = unsafe { &mut *world.get() }; - apply_system_buffers(&self.unapplied_systems, systems, world); - self.unapplied_systems.clear(); - debug_assert!(self.unapplied_systems.is_clear()); - - debug_assert!(self.ready_systems.is_clear()); - debug_assert!(self.running_systems.is_clear()); - self.active_access.clear(); - self.evaluated_sets.clear(); - self.skipped_systems.clear(); - self.completed_systems.clear(); }; #[cfg(feature = "trace")] @@ -199,6 +186,20 @@ impl SystemExecutor for MultiThreadedExecutor { let executor = executor.instrument(executor_span); scope.spawn(executor); }); + + // Do one final apply buffers after all systems have completed + // SAFETY: all systems have completed, and so no outstanding accesses remain + let world = unsafe { &mut *world.get() }; + apply_system_buffers(&self.unapplied_systems, systems, world); + self.unapplied_systems.clear(); + debug_assert!(self.unapplied_systems.is_clear()); + + debug_assert!(self.ready_systems.is_clear()); + debug_assert!(self.running_systems.is_clear()); + self.active_access.clear(); + self.evaluated_sets.clear(); + self.skipped_systems.clear(); + self.completed_systems.clear(); } }