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

Prevent conflicting system resource parameters #864

Merged
merged 1 commit into from
Nov 15, 2020

Conversation

memoryruins
Copy link
Contributor

@memoryruins memoryruins commented Nov 14, 2020

Currently, a system is allowed to have multiple resource parameters to the same resource type. No current checks prevent multiple mutable borrows aliasing the same resource. Surprisingly, this applies to multiple local resources too in a slightly different way.

examples
#[derive(Default)]
pub struct Buffer(Vec<u8>);

// builds without an error and goes uncaught by runtime checks.
fn system(a: Res<Buffer>, mut b: ResMut<Buffer>, mut c: ResMut<Buffer>) {
    // heck, two aliasing mutable borrows + a shared borrowed
    let x: &Vec<u8> = &a.0;
    let y: &mut Vec<u8> = &mut b.0;
    let z: &mut Vec<u8> = &mut c.0;
    dbg!(x.len());
    y.push(42);
    z.push(42);
    dbg!(x.len());
}
pub fn system(mut a: Local<Buffer>, mut b: Local<Buffer>) {
    let a = &mut a.0;
    let b = &mut b.0;
    assert_eq!(a.len(), 0);
    assert_eq!(b.len(), 0);
    a.push(42);
    assert_eq!(a.len(), 1);'
    
     // this assert will fail because the two locals _are_ the same resource
    assert_eq!(b.len(), 0);
}

This PR adds access checks to the SystemParam::init implementation of Res, ResMut, ChangedRes, and Local.

Something I'm unsure about is how I split out the local type accesses. Without tracking local type access independently, a Local<Foo> and Res<Foo> would incorrectly lead to a conflict. Is that change appropriate or is tracking local resources needed for parallel schedulers checks?

@memoryruins memoryruins added the A-ECS Entities, components, systems, and events label Nov 14, 2020
@memoryruins

This comment has been minimized.

@memoryruins memoryruins marked this pull request as draft November 14, 2020 16:33
@memoryruins memoryruins marked this pull request as ready for review November 14, 2020 19:04
@memoryruins
Copy link
Contributor Author

This should prevent the issues pointed out in #598 (except for the issue title).
If splitting up the TypeAccess tracking for local resources is the correct course of action too, then it potentially resolves #483 as well.

@bonsairobo
Copy link
Contributor

I think it can be useful to have multiple copies of the same Res<T> in a SystemParam. It enables encapsulation for sub-objects.

#[derive(SystemParam)]
struct Outer<'a> {
    inner: Inner<'a>,
    foo: Res<'a, Foo>,
}

impl<'a> Outer<'a> {
    pub fn use_inner(&self) { self.inner.use_foo() }
}

mod inner {
    #[derive(SystemParam)]
    pub struct Inner<'a> {
        foo: Res<'a, Foo>,
    }

    impl<'a> Inner<'a> {
        pub fn use_foo(&self) {}
    }
}

@memoryruins
Copy link
Contributor Author

@bonsairobo do you have a fuller example? Inner is repeating the fields thar Outer already has access to.

@bonsairobo
Copy link
Contributor

I just mean that Inner might be some reusable SystemParam object, so you can build larger objects out of it. But sometimes both the inner and outer object need to access the same global resource. It shouldn't be a problem if it's Res, so disallowing this is limiting from a design perspective.

@memoryruins
Copy link
Contributor Author

memoryruins commented Nov 15, 2020

Makes sense ^^ it’s a small change to make the Res/ChangedRes checks look for only write accesses rather than reads/writes. I’ll push a change later today.

@memoryruins memoryruins force-pushed the system_resources branch 3 times, most recently from 4227d83 to 613cbd5 Compare November 15, 2020 13:04
@bonsairobo
Copy link
Contributor

@memoryruins Thanks for hearing me out. I only spoke up because I've run into this issue before with specs, and I found it annoying that it wouldn't let me read the same thing twice from the same system.

@cart
Copy link
Member

cart commented Nov 15, 2020

Very good call! Thanks 😄

If splitting up the TypeAccess tracking for local resources is the correct course of action too, then it potentially resolves #483 as well

Yeah I think this is a good call. Right now its fine to just ignore local resource access in the scheduler because there are only two ways to access Local resources:

  1. exclusive &mut World access
  2. via the Local SystemParam, which is restricted to accessing the current system's local resource.

If we ever add the ability to access arbitrary Local resources in query systems, then we will need to take that in to account.

@cart cart merged commit 4bdff66 into bevyengine:master Nov 15, 2020
@memoryruins memoryruins deleted the system_resources branch November 16, 2020 00:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-ECS Entities, components, systems, and events
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants