Skip to content

Commit 8d9f948

Browse files
Create new NonSendMarker (#18301)
# Objective Create new `NonSendMarker` that does not depend on `NonSend`. Required, in order to accomplish #17682. In that issue, we are trying to replace `!Send` resources with `thread_local!` in order to unblock the resources-as-components effort. However, when we remove all the `!Send` resources from a system, that allows the system to run on a thread other than the main thread, which is against the design of the system. So this marker gives us the control to require a system to run on the main thread without depending on `!Send` resources. ## Solution Create a new `NonSendMarker` to replace the existing one that does not depend on `NonSend`. ## Testing Other than running tests, I ran a few examples: - `window_resizing` - `wireframe` - `volumetric_fog` (looks so cool) - `rotation` - `button` There is a Mac/iOS-specific change and I do not have a Mac or iOS device to test it. I am doubtful that it would cause any problems for 2 reasons: 1. The change is the same as the non-wasm change which I did test 2. The Pixel Eagle tests run Mac tests But it wouldn't hurt if someone wanted to spin up an example that utilizes the `bevy_render` crate, which is where the Mac/iSO change was. ## Migration Guide If `NonSendMarker` is being used from `bevy_app::prelude::*`, replace it with `bevy_ecs::system::NonSendMarker` or use it from `bevy_ecs::prelude::*`. In addition to that, `NonSendMarker` does not need to be wrapped like so: ```rust fn my_system(_non_send_marker: Option<NonSend<NonSendMarker>>) { ... } ``` Instead, it can be used without any wrappers: ```rust fn my_system(_non_send_marker: NonSendMarker) { ... } ``` --------- Co-authored-by: Chris Russell <8494645+chescock@users.noreply.github.com>
1 parent 694db96 commit 8d9f948

File tree

5 files changed

+35
-11
lines changed

5 files changed

+35
-11
lines changed

crates/bevy_app/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,6 @@ pub mod prelude {
5858
RunFixedMainLoopSystem, SpawnScene, Startup, Update,
5959
},
6060
sub_app::SubApp,
61-
NonSendMarker, Plugin, PluginGroup, TaskPoolOptions, TaskPoolPlugin,
61+
Plugin, PluginGroup, TaskPoolOptions, TaskPoolPlugin,
6262
};
6363
}

crates/bevy_app/src/task_pool_plugin.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,19 @@ use crate::{App, Plugin};
33
use alloc::string::ToString;
44
use bevy_platform_support::sync::Arc;
55
use bevy_tasks::{AsyncComputeTaskPool, ComputeTaskPool, IoTaskPool, TaskPoolBuilder};
6-
use core::{fmt::Debug, marker::PhantomData};
6+
use core::fmt::Debug;
77
use log::trace;
88

99
cfg_if::cfg_if! {
1010
if #[cfg(not(all(target_arch = "wasm32", feature = "web")))] {
11-
use {crate::Last, bevy_ecs::prelude::NonSend, bevy_tasks::tick_global_task_pools_on_main_thread};
11+
use {crate::Last, bevy_tasks::tick_global_task_pools_on_main_thread};
12+
use bevy_ecs::system::NonSendMarker;
1213

1314
/// A system used to check and advanced our task pools.
1415
///
1516
/// Calls [`tick_global_task_pools_on_main_thread`],
1617
/// and uses [`NonSendMarker`] to ensure that this system runs on the main thread
17-
fn tick_global_task_pools(_main_thread_marker: Option<NonSend<NonSendMarker>>) {
18+
fn tick_global_task_pools(_main_thread_marker: NonSendMarker) {
1819
tick_global_task_pools_on_main_thread();
1920
}
2021
}
@@ -36,8 +37,6 @@ impl Plugin for TaskPoolPlugin {
3637
_app.add_systems(Last, tick_global_task_pools);
3738
}
3839
}
39-
/// A dummy type that is [`!Send`](Send), to force systems to run on the main thread.
40-
pub struct NonSendMarker(PhantomData<*mut ()>);
4140

4241
/// Defines a simple way to determine how many threads to use given the number of remaining cores
4342
/// and number of total cores

crates/bevy_ecs/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,8 @@ pub mod prelude {
9191
spawn::{Spawn, SpawnRelated},
9292
system::{
9393
Command, Commands, Deferred, EntityCommand, EntityCommands, In, InMut, InRef,
94-
IntoSystem, Local, NonSend, NonSendMut, ParamSet, Populated, Query, ReadOnlySystem,
95-
Res, ResMut, Single, System, SystemIn, SystemInput, SystemParamBuilder,
94+
IntoSystem, Local, NonSend, NonSendMarker, NonSendMut, ParamSet, Populated, Query,
95+
ReadOnlySystem, Res, ResMut, Single, System, SystemIn, SystemInput, SystemParamBuilder,
9696
SystemParamFunction, WithParamWarnPolicy,
9797
},
9898
world::{

crates/bevy_ecs/src/system/system_param.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1420,6 +1420,33 @@ unsafe impl<T: SystemBuffer> SystemParam for Deferred<'_, T> {
14201420
}
14211421
}
14221422

1423+
/// A dummy type that is [`!Send`](Send), to force systems to run on the main thread.
1424+
pub struct NonSendMarker;
1425+
1426+
// SAFETY: No world access.
1427+
unsafe impl SystemParam for NonSendMarker {
1428+
type State = ();
1429+
type Item<'w, 's> = Self;
1430+
1431+
#[inline]
1432+
fn init_state(_world: &mut World, system_meta: &mut SystemMeta) -> Self::State {
1433+
system_meta.set_non_send();
1434+
}
1435+
1436+
#[inline]
1437+
unsafe fn get_param<'world, 'state>(
1438+
_state: &'state mut Self::State,
1439+
_system_meta: &SystemMeta,
1440+
_world: UnsafeWorldCell<'world>,
1441+
_change_tick: Tick,
1442+
) -> Self::Item<'world, 'state> {
1443+
Self
1444+
}
1445+
}
1446+
1447+
// SAFETY: Does not read any world state
1448+
unsafe impl ReadOnlySystemParam for NonSendMarker {}
1449+
14231450
/// Shared borrow of a non-[`Send`] resource.
14241451
///
14251452
/// Only `Send` resources may be accessed with the [`Res`] [`SystemParam`]. In case that the

crates/bevy_render/src/view/window/mod.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -304,9 +304,7 @@ const DEFAULT_DESIRED_MAXIMUM_FRAME_LATENCY: u32 = 2;
304304
pub fn create_surfaces(
305305
// By accessing a NonSend resource, we tell the scheduler to put this system on the main thread,
306306
// which is necessary for some OS's
307-
#[cfg(any(target_os = "macos", target_os = "ios"))] _marker: Option<
308-
NonSend<bevy_app::NonSendMarker>,
309-
>,
307+
#[cfg(any(target_os = "macos", target_os = "ios"))] _marker: NonSendMarker,
310308
windows: Res<ExtractedWindows>,
311309
mut window_surfaces: ResMut<WindowSurfaces>,
312310
render_instance: Res<RenderInstance>,

0 commit comments

Comments
 (0)