bytecodealliance / bytecodealliance/wasmtime

Reconciling the removal of wasi-common with support for WASI threads

Open
#7,551 3 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

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

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.