bytecodealliance / bytecodealliance/wasmtime

Threading in a Scripting Environment

Open
#7,054 18 comments 0 reactions 0 assignees View on GitHub
Dominant language
Rust
Stars
18.6k
Forks
1.8k
Avg merge
1d 18h
Merged PRs (30d)
126

Description

The title basically says it, I've been attempting to block out a scripting system for a game engine the past few weeks and the current feature I've been attempting to figure out is multi-threading. And I can't seem to find any way to run two threads at once, that have access to the same data. This is the only requirement I'm trying to fulfill by any method.

The engine runs on ECS, so you have big shared arrays of data, operated upon by a bunch of scripts containing functions that interact with those arrays.

Ideally I'd like to accomplish two things, have systems/jobs called from separate threads be able to act on the shared data at the same time. And possibly multi thread access to data arrays within those systems/jobs.

My current setup is multiple wasm modules (one for each job/system, though I'm undecided if I need to segment them that much), with an imported shared array buffer so they're able to access each other's memory through pointers. Ideally built to raw wasm, not wasi, since I want to keep my experimental dependencies down, but for this threading exploration I switched to building wasi targets without entry points.

Initially I tried figuring out a way to multi-thread calls into the wasm runtime, but with the `&mut store` requirement that's not possible unless I want to risk some unsafe skirt around the borrow checker stuff.

So then I decided to try to build the job scheduling/thread pooling system inside of wasm, If I can't use threads outside I might as well use them inside right? After researching this, upgrading to wasi since I found out you need too, I looked into the wasmtime_wasi_threading crate and it seems intended (as all things wasi) for the entire application to be embedded in a wasm module. This doesn't really vibe with my "host runtime calling scripts" end goal. So that path of exploration has kind of ended as well. It also seems that an entirely different store is created for each thread (unverified through testing, but the source looks that way), and my understanding is that stores can't interact with each other, and that's my basic requirement.

I'm fully aware you can instantiate clones of a module in different stores, but again, the memory cant interact. I also know you can copy data but I just cringe instantly at that because with a game engine you really need that performance.

My question/issue is how do I access shared data from multiple threads. Does the wasi threading runtime do some black magic behind the scenes to share data and I just need to write my job scheduling system as a program that lives on another thread? Even then how would I interact with it while it's running?

My thoughts are that since SharedMemoryBuffer is already supposed to be thread-safe, threaded function calls modifying that should be fine, even for calls that would cause a memory allocation behind the scenes, so the &mut store lock is only really needed for loading or unloading new modules. I can totally see a system where I have the job scheduling system create multiple (unsafe) references to the store to be able to call functions from multiple threads, then periodically pause so that modules may be loaded or unloaded before continuing to make sure that no functions bug out while stuff is changing.

Is there an intended way to do this? Or is my use case unexplored territory? I'm also more than happy to get involved with the project and try to get something working if it's not possible currently.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.