bytecodealliance / bytecodealliance/wasmtime
Reconciling the removal of wasi-common with support for WASI threads
- Dominant language
- Rust
- Stars
- 18.6k
- Forks
- 1.8k
- Avg merge
- 1d 18h
- Merged PRs (30d)
- 126
Description
As part of the effort to implement the upcoming 0.2.0 version of WASI the previous implementation of WASI in Wasmtime, the `wasi-common` crate, was rewritten and is now located in the `wasmtime-wasi` crate in the `preview2` submodule. This means that Wasmtime (and the `wasmtime` CLI) now has two entirely separate implementations of the preview1 snapshot of WASI. This is not something I think we should retain indefinitely, so I think it's worthwhile to plan for the removal of the old `wasi-common` crate.
The only technical blocker I'm aware of for this is that the preview2-based implementation of `wasi_snapshot_preview1` does not support WASI threads. Effectively if a thread is spawned then all WASI functions will stop working because the WASI context is no longer uniquely owned. More-or-less this boils down to [this panic](https://github.com/bytecodealliance/wasmtime/blob/bba4ee78a98236e73540506ffebab91373791a82/src/commands/run.rs#L830) which would be dynamically triggered. There is no way right now to share the WASI context amongst threads and have functions continue to work (e.g. `poll` working concurrently on multiple threads).
There's definitely a lot of issues on the surface that look like incompatibilities, such as liberal usage of `&mut Table` and `&mut self`, but I think much of this can be updated with relative ease to work with `&Table` that has some internal synchronization which gives temporary access to `&mut self` on various objects. The main thing I don't know how to solve at this time, however, is how blocking works.
Currently all blocking computations in Wasmtime's implementation of WASI are represented as a `Future`. This is chiefly done through the `Subscribe` trait:
```rust
#[async_trait::async_trait]
pub trait Subscribe: Send + Sync + 'static {
async fn ready(&mut self);
}
```
The usage of `&mut self` here is problematic because the same I/O object could be subscribe to from multiple threads which means `&mut` exclusive access is not possible. More-or-less what theoretically needs to happen is to push the `&self` into this method to enable waiting for readiness on objects on multiple threads simultaenously. Each thread would create its own future in `poll` and then it'd get arbitrated internally. This is, however, a very large refactoring and departure from the current design, one that I don't think can easily be done and I think may have unknown consequences (e.g. more-than-expected overhead in the single-threaded use case).
This conclusion brings me to opening this issue for more discussion.
cc @abrown
Contributor guide
Assessment
This issue has not been assessed yet.