bevyengine / bevyengine/bevy

`single_threaded_task_pool` `scope` api doesn't work in wasm

Open
#1,924 14 comments 0 reactions 0 assignees View on GitHub
A-App C-Bug O-Web
Dominant language
Rust
Stars
48.2k
Forks
4.8k
Avg merge
3d 16h
Merged PRs (30d)
171

Description

## Bevy version

0.5 and `d119c1ce14da59089a65373d59715a41d05251ad`

## Operating system & version

Firefox & Chromium

## What you did

Trying to use the task pool to execute several tasks, I hoped to have the same code running in both wasm and native
```rust
use bevy::{prelude::*, tasks::prelude::*};

fn main() {
let mut builder = App::build();
builder.add_plugins(DefaultPlugins);

let asset_io = bevy::asset::create_platform_default_asset_io(&mut builder);

builder
.insert_resource(asset_io)
.init_resource::>()
.add_startup_system(get_from_future.system())
.add_system(log_stuff.system())
.run();
}

fn get_from_future(
task_pool: Res,
mut expensive_to_get: ResMut>,
asset_io: Res>,
) {
let asset_io = &*asset_io;
*expensive_to_get = task_pool
.scope(|scope| {
for i in 0..3 {
scope.spawn(async move {
std::str::from_utf8(
&asset_io
.load_path(&std::path::Path::new(&format!("file_{}.big", i)))
.await
.unwrap(),
)
.unwrap()
.to_string()
});
}
})
.into_iter()
.collect();
}

fn log_stuff(expensive_to_get: Res>) {
bevy::log::warn!("got {:?}", *expensive_to_get);
}
```

This works on native!

Building this for wasm32 gives an error:
```
26 | scope.spawn(async move {
| ^^^^^ future created by async block is not `Send`
```

Indeed, `spawn` requires the future to be `Send` in the single_threaded_task_pool. This could probably be removed anyway as it calls `spawn_local` which doesn't need `Send`
https://github.com/bevyengine/bevy/blob/d119c1ce14da59089a65373d59715a41d05251ad/crates/bevy_tasks/src/single_threaded_task_pool.rs#L129-L131

Let's try to run this with `spawn_local` to check if it would work better.At least it compiles that way!

And crash in the browser
```
test.js:276 panicked at 'assertion failed: `(left == right)`
left: `true`,
right: `false`: cannot recursively acquire mutex',
```

And rightly so. In the `scope` function:
https://github.com/bevyengine/bevy/blob/d119c1ce14da59089a65373d59715a41d05251ad/crates/bevy_tasks/src/single_threaded_task_pool.rs#L79-L83
The `lock()` is on a mutex, and that can't work because you can't block in wasm...

Using the task pool in wasm will work for trivial task that aren't long enough to lock the mutex, but will fail for any real case...

I tried a few things but couldn't get it to work

Contributor guide

Open the contributing guide

Research direction

Start in crates/bevy_tasks/src/single_threaded_task_pool.rs, especially scope and its spawn path, then compare the wasm behavior with spawn_local. Reproduce the provided task-pool example in wasm and investigate the recursive mutex assertion in the browser. Done means scoped tasks compile and run in wasm without blocking or panicking, while native behavior remains working.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust, wasm
Domain
backend, game-dev
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.