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

Using rendy on multiple threads at same time causes segfault #151

Open
azriel91 opened this issue May 27, 2019 · 4 comments
Open

Using rendy on multiple threads at same time causes segfault #151

azriel91 opened this issue May 27, 2019 · 4 comments
Labels
bug Something isn't working diff: hard

Comments

@azriel91
Copy link
Member

azriel91 commented May 27, 2019

Symptom

Given:

  • 2 or more threads
  • each thread uses rendy at the same time

Then sometimes one thread's resource cleanup interferes with the other thread's usage.

Steps to Reproduce

This crate just has 100 test functions with an empty GraphBuilder

git clone git@github.com:azriel91/amethyst_rendy_test.git
cd amethyst_rendy_test
cargo update # in case you already had it
cargo test -- --nocapture
# should segfault, if not run it again

# proof that it doesn't segfault with 1 thread:
cargo test -- --nocapture --test-threads 1

Theory

Multiple threads share a common "memory space" (? I don't understand rendy enough). When one is cleaning up, another might be setting up, causing Terminal to be disposed while some Escape values are created.

Note:

When run single threaded (cargo test -- --test-threads 1) with the empty graph, it doesn't segfault.
Further evidence that rendy is correctly disposing in the correct order if you follow the serial control flow.

When run single threaded with RenderTestBundle, which has the sprites and PresentNode in the graph, it does segfault.

Logs

...
[ERROR][rendy_resource::escape] Terminal must be dropped after all `Escape`s
[ERROR][rendy_resource::escape] Terminal must be dropped after all `Escape`s
[ERROR][rendy_memory::allocator::dynamic] Memory leak: SizeEntry(8192) is still used
[ERROR][rendy_memory::allocator::dynamic] Memory leak: SizeEntry(1024) is still used
[ERROR][rendy_memory::allocator::dynamic] Memory leak: SizeEntry(65536) is still used
[ERROR][rendy_memory::allocator::dynamic] Memory leak: SizeEntry(524288) is still used
[ERROR][rendy_memory::allocator::dynamic] Memory leak: SizeEntry(4194304) is still used
[ERROR][rendy_resource::escape] `Escape` was dropped after a `Terminal`?
...

Environment

  • OS: Windows
  • Rendy version: master
@zakarumych
Copy link
Member

zakarumych commented May 27, 2019

Cleanup methods require exclusive access to factory.
If you create separate factories then rendy share nothing, except atomic integer to generate ids, but backend can share something.

@crsaracco
Copy link

Not sure how related this is, but I also got this while generating meshes and materials. Would something like this run in multiple threads?

struct GameState;
impl SimpleState for GameState {
    fn on_start(&mut self, state_data: StateData<'_, GameData<'_, '_>>) {
        initialize_camera(state_data.world);

        for x in -1..2 {
            for y in -1..2 {
                for z in -1..2 {
                    initialize_cube(state_data.world, x as f32 * 3.0, y as f32 * 3.0, z as f32 * 3.0);
                }
            }
        }

        initialize_light(state_data.world);
    }
}

fn initialize_cube(world: &mut World, x: f32, y: f32, z: f32) {
    let mesh = world.exec(|loader: AssetLoaderSystemData<'_, Mesh>| {
        loader.load_from_data(
            Shape::Cube
                .generate::<(Vec<Position>, Vec<Normal>, Vec<Tangent>, Vec<TexCoord>)>(None)
                .into(),
            (),
        )
    });

    let albedo = material_generator::albedo(world, 1.0, 0.0, 0.0, 1.0);
    let metallic_roughness = material_generator::metallic_roughness(world, 0.5, 0.5);
    let material = material_generator::generate_material(world, albedo, metallic_roughness);

    let mut transform = Transform::default();
    transform.set_translation_xyz(x, y, z);

    world
        .create_entity()
        .with(mesh)
        .with(material)
        .with(transform)
        .build();
}

// `metallic_roughness` and `generate_material` look similar
pub fn albedo(world: &mut World, red: f32, green: f32, blue: f32, alpha: f32) -> Handle<Texture> {
    let albedo = world.exec(|loader: AssetLoaderSystemData<'_, Texture>| {
        loader.load_from_data(
            load_from_linear_rgba(LinSrgba::new(red, green, blue, alpha)).into(),
            (),
        )
    });
    albedo
}

@carnoxen
Copy link

carnoxen commented Aug 23, 2020

Hi, I want to ask for an error. I compiled this project, but got this error ⬇

[ERROR][rendy_resource::escape] Terminal must be dropped after all `Escape`s
[ERROR][rendy_resource::escape] Terminal must be dropped after all `Escape`s
[ERROR][rendy_resource::escape] Terminal must be dropped after all `Escape`s
[ERROR][rendy_resource::escape] Terminal must be dropped after all `Escape`s
[ERROR][rendy_resource::escape] Terminal must be dropped after all `Escape`s
[ERROR][rendy_resource::escape] Terminal must be dropped after all `Escape`s

It seems related about this issue, so is there anything for fixing this?

@fu5ha
Copy link
Member

fu5ha commented Aug 23, 2020 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working diff: hard
Projects
None yet
Development

No branches or pull requests

6 participants