Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Merged by Bors] - Panic on dropping NonSend in non-origin thread. #6534

Closed
wants to merge 57 commits into from
Closed
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
bbb7e85
Abort on dropping NonSend in non-origin thread.
james7132 Nov 10, 2022
0f4b73d
Fix safety comments
james7132 Nov 10, 2022
e83e8e3
Invert is_send
james7132 Nov 10, 2022
e46ec0c
Factor out drop-abort
james7132 Nov 10, 2022
0898a54
Fix access, replace MainThreadValidator
james7132 Nov 16, 2022
e4d61c1
Update docs
james7132 Nov 16, 2022
944b83c
Switch to always panic, use ManuallyDrop
james7132 Nov 16, 2022
9b712df
Formatting
james7132 Nov 16, 2022
776ffaf
Merge branch 'main' into abort-on-nonsend-drop
james7132 Dec 1, 2022
ba27136
Split out into NonSendResources
james7132 Dec 2, 2022
c3708d4
Cleanup docs and type definitions
james7132 Dec 2, 2022
16ae491
Fix CI
james7132 Dec 2, 2022
cc4c611
Merge branch 'main' into abort-on-nonsend-drop
james7132 Dec 2, 2022
1a09486
Update safety docs.
james7132 Dec 2, 2022
f935aa2
Actually fix CI
james7132 Dec 2, 2022
f4281e6
Small cleanup
james7132 Dec 2, 2022
1692da8
Fix WorldCell's use of NonSend
james7132 Dec 2, 2022
2b11ea3
Fix bevy_window
james7132 Dec 2, 2022
638e95c
Use const generics to split on Send/!Send
james7132 Dec 2, 2022
c37f26e
Use const generics instead of duplicating code
james7132 Dec 2, 2022
ee5de65
Use the right branch
james7132 Dec 2, 2022
d195cb6
Add panic sections to World's API docs
james7132 Dec 3, 2022
93334a0
Apply suggestions from code review
james7132 Dec 3, 2022
8f72292
Remove non_send_scope
james7132 Dec 3, 2022
b3fffd9
Split insert_non_send_by_id from insert_resource_by_id
james7132 Dec 3, 2022
54e5a50
Fix safety comment and tests
james7132 Dec 3, 2022
5f6e91b
Exhaustively decompose Storages in check_change_ticks
james7132 Dec 3, 2022
cfb8173
Remove spurious is_send in docs
james7132 Dec 3, 2022
5900696
Update safety docs on initialize_resource_internal
james7132 Dec 3, 2022
95e575f
Check that Send resources have correct metadata on initialization
james7132 Dec 3, 2022
2bff28c
Formatting
james7132 Dec 3, 2022
6af4c4e
Undo changes to BlobVec, how the hell did this get in here
james7132 Dec 3, 2022
e056626
Fix docs link
james7132 Dec 3, 2022
58bcb66
Apply suggestions from code review
james7132 Dec 4, 2022
9db8041
Stronger assert
james7132 Dec 4, 2022
d713d84
Fix CI
james7132 Dec 4, 2022
314a86e
Apply suggestions from code review
james7132 Dec 5, 2022
e06677a
Small cleanup
james7132 Dec 5, 2022
de05d57
Update crates/bevy_ecs/src/world/mod.rs
james7132 Dec 5, 2022
b4d6303
Merge branch 'main' into abort-on-nonsend-drop
james7132 Dec 6, 2022
a9895c0
Merge branch 'abort-on-nonsend-drop' of github.com:james7132/bevy int…
james7132 Dec 7, 2022
db4c6d7
Apply suggestions from code review
james7132 Dec 8, 2022
7578306
Merge branch 'main' into abort-on-nonsend-drop
james7132 Dec 8, 2022
5e182fc
Move std::thread::panicking check to Drop impl
james7132 Dec 8, 2022
263ed85
Update safety comment about validate_access in Drop
james7132 Dec 8, 2022
e4a0a9a
Add the missing get_non_send_by_id APIs
james7132 Dec 8, 2022
5be8450
Formatting
james7132 Dec 8, 2022
587ea78
Add test for distinct storage and missing panic comments
james7132 Dec 8, 2022
68de55f
Make the safety comments on _by_id APIs more accurate
james7132 Dec 9, 2022
4e8412f
Reword panic docs.
james7132 Dec 12, 2022
ebe33dd
Merge branch 'main' into abort-on-nonsend-drop
james7132 Dec 12, 2022
87c88ab
Fix CI
james7132 Dec 12, 2022
6d39cd5
Merge branch 'main' into abort-on-nonsend-drop
james7132 Dec 19, 2022
8b8a735
Revert changes with NonSendMarker
james7132 Dec 19, 2022
6c8e988
Merge branch 'main' into abort-on-nonsend-drop
james7132 Jan 2, 2023
2c5be6d
Formatting
james7132 Jan 2, 2023
b236f9d
Merge branch 'main' into abort-on-nonsend-drop
james7132 Jan 9, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 33 additions & 1 deletion crates/bevy_ecs/src/storage/resource.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,40 @@ use crate::archetype::ArchetypeComponentId;
use crate::component::{ComponentId, ComponentTicks, Components};
use crate::storage::{Column, SparseSet};
use bevy_ptr::{OwningPtr, Ptr, UnsafeCellDeref};
use bevy_utils::tracing::error;
use std::cell::UnsafeCell;
use std::thread::ThreadId;

/// The type-erased backing storage and metadata for a single resource within a [`World`].
///
/// [`World`]: crate::world::World
pub struct ResourceData {
column: Column,
id: ArchetypeComponentId,
origin_thread_id: Option<ThreadId>,
}

impl Drop for ResourceData {
fn drop(&mut self) {
self.validate_drop();
}
}

impl ResourceData {
#[inline]
fn validate_drop(&self) {
if let Some(origin_thread_id) = self.origin_thread_id {
if origin_thread_id != std::thread::current().id() {
error!(
"Attempted to drop non-send resource from thread {:?} on a thread {:?}. This is not allowed. Aborting.",
origin_thread_id,
std::thread::current().id()
);
std::process::abort();
}
}
}

/// Returns true if the resource is populated.
#[inline]
pub fn is_present(&self) -> bool {
Expand Down Expand Up @@ -60,6 +83,9 @@ impl ResourceData {
/// [`World::validate_non_send_access_untyped`]: crate::world::World::validate_non_send_access_untyped
#[inline]
pub(crate) unsafe fn insert(&mut self, value: OwningPtr<'_>, change_tick: u32) {
if self.origin_thread_id.is_some() {
self.origin_thread_id = Some(std::thread::current().id());
}
james7132 marked this conversation as resolved.
Show resolved Hide resolved
if self.is_present() {
self.column.replace(0, value, change_tick);
} else {
Expand Down Expand Up @@ -115,6 +141,7 @@ impl ResourceData {
/// [`World::validate_non_send_access_untyped`]: crate::world::World::validate_non_send_access_untyped
#[inline]
pub(crate) unsafe fn remove_and_drop(&mut self) {
self.validate_drop();
self.column.clear();
}
}
Expand Down Expand Up @@ -162,17 +189,22 @@ impl Resources {
///
/// # Panics
/// Will panic if `component_id` is not valid for the provided `components`
pub(crate) fn initialize_with(
///
/// # Safety
/// `is_send` must be accurate for the Resource that is being initialized.
pub(crate) unsafe fn initialize_with(
&mut self,
component_id: ComponentId,
components: &Components,
is_send: bool,
f: impl FnOnce() -> ArchetypeComponentId,
) -> &mut ResourceData {
self.resources.get_or_insert_with(component_id, || {
let component_info = components.get_info(component_id).unwrap();
ResourceData {
column: Column::with_capacity(component_info, 1),
id: f(),
origin_thread_id: (!is_send).then(|| std::thread::current().id()),
}
})
}
Expand Down
27 changes: 16 additions & 11 deletions crates/bevy_ecs/src/world/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -739,7 +739,7 @@ impl World {
OwningPtr::make(value, |ptr| {
// SAFETY: component_id was just initialized and corresponds to resource of type R
unsafe {
self.insert_resource_by_id(component_id, ptr);
self.insert_resource_by_id(component_id, true, ptr);
james7132 marked this conversation as resolved.
Show resolved Hide resolved
}
});
}
Expand Down Expand Up @@ -779,7 +779,7 @@ impl World {
OwningPtr::make(value, |ptr| {
// SAFETY: component_id was just initialized and corresponds to resource of type R
unsafe {
self.insert_resource_by_id(component_id, ptr);
self.insert_resource_by_id(component_id, false, ptr);
}
});
}
Expand Down Expand Up @@ -1311,31 +1311,36 @@ impl World {
///
/// # Safety
/// The value referenced by `value` must be valid for the given [`ComponentId`] of this world
/// `component_id` must exist in this [`World`]
/// `component_id` must exist in this [`World`]. `is_send` must correspond to whether the resource
/// adheres to invariants of `Send`.
#[inline]
pub unsafe fn insert_resource_by_id(
&mut self,
component_id: ComponentId,
is_send: bool,
james7132 marked this conversation as resolved.
Show resolved Hide resolved
value: OwningPtr<'_>,
) {
let change_tick = self.change_tick();

// SAFETY: component_id is valid, ensured by caller
self.initialize_resource_internal(component_id)
// SAFETY: component_id and is_send are valid, ensured by caller
self.initialize_resource_internal(component_id, is_send)
.insert(value, change_tick);
}

/// # Safety
/// `component_id` must be valid for this world
/// `is_send` should correspond for the resource being initialized.
james7132 marked this conversation as resolved.
Show resolved Hide resolved
#[inline]
unsafe fn initialize_resource_internal(
&mut self,
component_id: ComponentId,
is_send: bool,
) -> &mut ResourceData {
let archetype_component_count = &mut self.archetypes.archetype_component_count;
// SAFETY: Caller guarentees that `is_send` matches the underlying type.
james7132 marked this conversation as resolved.
Show resolved Hide resolved
self.storages
.resources
.initialize_with(component_id, &self.components, || {
.initialize_with(component_id, &self.components, is_send, || {
let id = ArchetypeComponentId::new(*archetype_component_count);
*archetype_component_count += 1;
id
Expand All @@ -1344,15 +1349,15 @@ impl World {

pub(crate) fn initialize_resource<R: Resource>(&mut self) -> ComponentId {
let component_id = self.components.init_resource::<R>();
// SAFETY: resource initialized above
unsafe { self.initialize_resource_internal(component_id) };
// SAFETY: resource initialized above, resource type must be Send
unsafe { self.initialize_resource_internal(component_id, true) };
component_id
}

pub(crate) fn initialize_non_send_resource<R: 'static>(&mut self) -> ComponentId {
let component_id = self.components.init_non_send::<R>();
// SAFETY: resource initialized above
unsafe { self.initialize_resource_internal(component_id) };
// SAFETY: resource initialized above, resource type might not be send
unsafe { self.initialize_resource_internal(component_id, false) };
component_id
}

Expand Down Expand Up @@ -1794,7 +1799,7 @@ mod tests {
OwningPtr::make(value, |ptr| {
// SAFETY: value is valid for the component layout
unsafe {
world.insert_resource_by_id(component_id, ptr);
world.insert_resource_by_id(component_id, true, ptr);
james7132 marked this conversation as resolved.
Show resolved Hide resolved
}
});

Expand Down