Use new run_without_applying_deferred method in SingleThreadedExecutor (#18684)

# Objective

Simplify code in the `SingleThreadedExecutor` by removing a special case
for exclusive systems.

The `SingleThreadedExecutor` runs systems without immediately applying
deferred buffers. That required calling `run_unsafe()` instead of
`run()`, but that would `panic` for exclusive systems, so the code also
needed a special case for those. Following #18076 and #18406, we have a
`run_without_applying_deferred` method that has the exact behavior we
want and works on exclusive systems.

## Solution

Replace the code in `SingleThreadedExecutor` that runs systems with a
single call to `run_without_applying_deferred()`. Also add this as a
wrapper in the `__rust_begin_short_backtrace` module to preserve the
special behavior for backtraces.
This commit is contained in:
Chris Russell 2025-05-05 20:09:02 -04:00 committed by GitHub
parent 49f1827633
commit 3442e2556d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 32 additions and 32 deletions

View File

@ -271,38 +271,54 @@ impl IntoSystemSet<()> for ApplyDeferred {
mod __rust_begin_short_backtrace { mod __rust_begin_short_backtrace {
use core::hint::black_box; use core::hint::black_box;
#[cfg(feature = "std")]
use crate::world::unsafe_world_cell::UnsafeWorldCell;
use crate::{ use crate::{
error::Result, error::Result,
system::{ReadOnlySystem, ScheduleSystem}, system::{ReadOnlySystem, ScheduleSystem},
world::{unsafe_world_cell::UnsafeWorldCell, World}, world::World,
}; };
/// # Safety /// # Safety
/// See `System::run_unsafe`. /// See `System::run_unsafe`.
// This is only used by `MultiThreadedExecutor`, and would be dead code without `std`.
#[cfg(feature = "std")]
#[inline(never)] #[inline(never)]
pub(super) unsafe fn run_unsafe(system: &mut ScheduleSystem, world: UnsafeWorldCell) -> Result { pub(super) unsafe fn run_unsafe(system: &mut ScheduleSystem, world: UnsafeWorldCell) -> Result {
let result = system.run_unsafe((), world); let result = system.run_unsafe((), world);
// Call `black_box` to prevent this frame from being tail-call optimized away
black_box(()); black_box(());
result result
} }
/// # Safety /// # Safety
/// See `ReadOnlySystem::run_unsafe`. /// See `ReadOnlySystem::run_unsafe`.
#[cfg_attr( // This is only used by `MultiThreadedExecutor`, and would be dead code without `std`.
not(feature = "std"), #[cfg(feature = "std")]
expect(dead_code, reason = "currently only used with the std feature")
)]
#[inline(never)] #[inline(never)]
pub(super) unsafe fn readonly_run_unsafe<O: 'static>( pub(super) unsafe fn readonly_run_unsafe<O: 'static>(
system: &mut dyn ReadOnlySystem<In = (), Out = O>, system: &mut dyn ReadOnlySystem<In = (), Out = O>,
world: UnsafeWorldCell, world: UnsafeWorldCell,
) -> O { ) -> O {
// Call `black_box` to prevent this frame from being tail-call optimized away
black_box(system.run_unsafe((), world)) black_box(system.run_unsafe((), world))
} }
#[inline(never)] #[inline(never)]
pub(super) fn run(system: &mut ScheduleSystem, world: &mut World) -> Result { pub(super) fn run(system: &mut ScheduleSystem, world: &mut World) -> Result {
let result = system.run((), world); let result = system.run((), world);
// Call `black_box` to prevent this frame from being tail-call optimized away
black_box(());
result
}
#[inline(never)]
pub(super) fn run_without_applying_deferred(
system: &mut ScheduleSystem,
world: &mut World,
) -> Result {
let result = system.run_without_applying_deferred((), world);
// Call `black_box` to prevent this frame from being tail-call optimized away
black_box(()); black_box(());
result result
} }
@ -312,6 +328,7 @@ mod __rust_begin_short_backtrace {
system: &mut dyn ReadOnlySystem<In = (), Out = O>, system: &mut dyn ReadOnlySystem<In = (), Out = O>,
world: &mut World, world: &mut World,
) -> O { ) -> O {
// Call `black_box` to prevent this frame from being tail-call optimized away
black_box(system.run((), world)) black_box(system.run((), world))
} }
} }

View File

@ -128,33 +128,16 @@ impl SystemExecutor for SingleThreadedExecutor {
} }
let f = AssertUnwindSafe(|| { let f = AssertUnwindSafe(|| {
if system.is_exclusive() { if let Err(err) =
if let Err(err) = __rust_begin_short_backtrace::run(system, world) { __rust_begin_short_backtrace::run_without_applying_deferred(system, world)
error_handler( {
err, error_handler(
ErrorContext::System { err,
name: system.name(), ErrorContext::System {
last_run: system.get_last_run(), name: system.name(),
}, last_run: system.get_last_run(),
); },
} );
} else {
// Use run_unsafe to avoid immediately applying deferred buffers
let world = world.as_unsafe_world_cell();
system.update_archetype_component_access(world);
// SAFETY: We have exclusive, single-threaded access to the world and
// update_archetype_component_access is being called immediately before this.
unsafe {
if let Err(err) = __rust_begin_short_backtrace::run_unsafe(system, world) {
error_handler(
err,
ErrorContext::System {
name: system.name(),
last_run: system.get_last_run(),
},
);
}
};
} }
}); });