bevy_ecs/schedule/executor/mod.rs
1mod multi_threaded;
2mod simple;
3mod single_threaded;
4
5pub use self::multi_threaded::{MainThreadExecutor, MultiThreadedExecutor};
6pub use self::simple::SimpleExecutor;
7pub use self::single_threaded::SingleThreadedExecutor;
8
9use fixedbitset::FixedBitSet;
10
11use crate::{
12 schedule::{BoxedCondition, NodeId},
13 system::BoxedSystem,
14 world::World,
15};
16
17/// Types that can run a [`SystemSchedule`] on a [`World`].
18pub(super) trait SystemExecutor: Send + Sync {
19 fn kind(&self) -> ExecutorKind;
20 fn init(&mut self, schedule: &SystemSchedule);
21 fn run(
22 &mut self,
23 schedule: &mut SystemSchedule,
24 world: &mut World,
25 skip_systems: Option<&FixedBitSet>,
26 );
27 fn set_apply_final_deferred(&mut self, value: bool);
28}
29
30/// Specifies how a [`Schedule`](super::Schedule) will be run.
31///
32/// The default depends on the target platform:
33/// - [`SingleThreaded`](ExecutorKind::SingleThreaded) on WASM.
34/// - [`MultiThreaded`](ExecutorKind::MultiThreaded) everywhere else.
35#[derive(PartialEq, Eq, Default, Debug, Copy, Clone)]
36pub enum ExecutorKind {
37 /// Runs the schedule using a single thread.
38 ///
39 /// Useful if you're dealing with a single-threaded environment, saving your threads for
40 /// other things, or just trying minimize overhead.
41 #[cfg_attr(any(target_arch = "wasm32", not(feature = "multi_threaded")), default)]
42 SingleThreaded,
43 /// Like [`SingleThreaded`](ExecutorKind::SingleThreaded) but calls [`apply_deferred`](crate::system::System::apply_deferred)
44 /// immediately after running each system.
45 Simple,
46 /// Runs the schedule using a thread pool. Non-conflicting systems can run in parallel.
47 #[cfg_attr(all(not(target_arch = "wasm32"), feature = "multi_threaded"), default)]
48 MultiThreaded,
49}
50
51/// Holds systems and conditions of a [`Schedule`](super::Schedule) sorted in topological order
52/// (along with dependency information for `multi_threaded` execution).
53///
54/// Since the arrays are sorted in the same order, elements are referenced by their index.
55/// [`FixedBitSet`] is used as a smaller, more efficient substitute of `HashSet<usize>`.
56#[derive(Default)]
57pub struct SystemSchedule {
58 /// List of system node ids.
59 pub(super) system_ids: Vec<NodeId>,
60 /// Indexed by system node id.
61 pub(super) systems: Vec<BoxedSystem>,
62 /// Indexed by system node id.
63 pub(super) system_conditions: Vec<Vec<BoxedCondition>>,
64 /// Indexed by system node id.
65 /// Number of systems that the system immediately depends on.
66 pub(super) system_dependencies: Vec<usize>,
67 /// Indexed by system node id.
68 /// List of systems that immediately depend on the system.
69 pub(super) system_dependents: Vec<Vec<usize>>,
70 /// Indexed by system node id.
71 /// List of sets containing the system that have conditions
72 pub(super) sets_with_conditions_of_systems: Vec<FixedBitSet>,
73 /// List of system set node ids.
74 pub(super) set_ids: Vec<NodeId>,
75 /// Indexed by system set node id.
76 pub(super) set_conditions: Vec<Vec<BoxedCondition>>,
77 /// Indexed by system set node id.
78 /// List of systems that are in sets that have conditions.
79 ///
80 /// If a set doesn't run because of its conditions, this is used to skip all systems in it.
81 pub(super) systems_in_sets_with_conditions: Vec<FixedBitSet>,
82}
83
84impl SystemSchedule {
85 /// Creates an empty [`SystemSchedule`].
86 pub const fn new() -> Self {
87 Self {
88 systems: Vec::new(),
89 system_conditions: Vec::new(),
90 set_conditions: Vec::new(),
91 system_ids: Vec::new(),
92 set_ids: Vec::new(),
93 system_dependencies: Vec::new(),
94 system_dependents: Vec::new(),
95 sets_with_conditions_of_systems: Vec::new(),
96 systems_in_sets_with_conditions: Vec::new(),
97 }
98 }
99}
100
101/// Instructs the executor to call [`System::apply_deferred`](crate::system::System::apply_deferred)
102/// on the systems that have run but not applied their [`Deferred`](crate::system::Deferred) system parameters
103/// (like [`Commands`](crate::prelude::Commands)) or other system buffers.
104///
105/// ## Scheduling
106///
107/// `apply_deferred` systems are scheduled *by default*
108/// - later in the same schedule run (for example, if a system with `Commands` param
109/// is scheduled in `Update`, all the changes will be visible in `PostUpdate`)
110/// - between systems with dependencies if the dependency
111/// [has deferred buffers](crate::system::System::has_deferred)
112/// (if system `bar` directly or indirectly depends on `foo`, and `foo` uses `Commands` param,
113/// changes to the world in `foo` will be visible in `bar`)
114///
115/// ## Notes
116/// - This function (currently) does nothing if it's called manually or wrapped inside a [`PipeSystem`](crate::system::PipeSystem).
117/// - Modifying a [`Schedule`](super::Schedule) may change the order buffers are applied.
118#[doc(alias = "apply_system_buffers")]
119#[allow(unused_variables)]
120pub fn apply_deferred(world: &mut World) {}
121
122/// Returns `true` if the [`System`](crate::system::System) is an instance of [`apply_deferred`].
123pub(super) fn is_apply_deferred(system: &BoxedSystem) -> bool {
124 use crate::system::IntoSystem;
125 // deref to use `System::type_id` instead of `Any::type_id`
126 system.as_ref().type_id() == apply_deferred.system_type_id()
127}
128
129/// These functions hide the bottom of the callstack from `RUST_BACKTRACE=1` (assuming the default panic handler is used).
130/// The full callstack will still be visible with `RUST_BACKTRACE=full`.
131/// They are specialized for `System::run` & co instead of being generic over closures because this avoids an
132/// extra frame in the backtrace.
133///
134/// This is reliant on undocumented behavior in Rust's default panic handler, which checks the call stack for symbols
135/// containing the string `__rust_begin_short_backtrace` in their mangled name.
136mod __rust_begin_short_backtrace {
137 use std::hint::black_box;
138
139 use crate::{
140 system::{ReadOnlySystem, System},
141 world::{unsafe_world_cell::UnsafeWorldCell, World},
142 };
143
144 /// # Safety
145 /// See `System::run_unsafe`.
146 #[inline(never)]
147 pub(super) unsafe fn run_unsafe(
148 system: &mut dyn System<In = (), Out = ()>,
149 world: UnsafeWorldCell,
150 ) {
151 system.run_unsafe((), world);
152 black_box(());
153 }
154
155 /// # Safety
156 /// See `ReadOnlySystem::run_unsafe`.
157 #[inline(never)]
158 pub(super) unsafe fn readonly_run_unsafe<O: 'static>(
159 system: &mut dyn ReadOnlySystem<In = (), Out = O>,
160 world: UnsafeWorldCell,
161 ) -> O {
162 black_box(system.run_unsafe((), world))
163 }
164
165 #[inline(never)]
166 pub(super) fn run(system: &mut dyn System<In = (), Out = ()>, world: &mut World) {
167 system.run((), world);
168 black_box(());
169 }
170
171 #[inline(never)]
172 pub(super) fn readonly_run<O: 'static>(
173 system: &mut dyn ReadOnlySystem<In = (), Out = O>,
174 world: &mut World,
175 ) -> O {
176 black_box(system.run((), world))
177 }
178}