This PR ports Lucet to use those new capabilities of wiggle and wasi-common, where the entire host function is an async fn executed on the host stack via Vmctx::block_on. This is a significant departure from the existing Lucet async style of only using Vmctx::block_on in small sections. However, it is also currently impossible to use the Wiggle module traits as defined by upstream wasi-common, because currently Wasmtime does not require async host functions to impl Send, and in fact they close over WasiCtx which is not safe to Send.
To solve this impedance mismatch, this PR vendors in the changes made to the wiggle and wasi-common family of crates by @alexcrichton in https://github.com/bytecodealliance/wasmtime/pull/2897. These changes transform Wiggle module traits to take &mut self rather than &self, and simplify the structure of WasiCtx so that it does now impl Send. So, this version of upstream is compatible with Lucet, but since it is gated behind RFC11 we are vendoring it until it lands. All references to the wiggle{-} and wasi- crates in the Lucet workspace have been changed to paths in the wasmtime-new-api directory.
lucet-wiggle was previously a bit clunky due to constraints in wiggle which went away a while ago. It has been redesigned to work just like wasmtime-wiggle: it re-exports wiggle, and provides its own lucet_integration! proc macro which only defines the code which hooks up the code generated from wiggle::from_witx! to the lucet runtime. Previously lucet-wiggle shipped its own from_witx! macro which combined both of those macros into one.
That change also meant we can get rid of lucet-wasi-generate entirely! No more special proc macro or boilerplate is required for hooking up the wasi-common definitions directly as Lucet hostcalls - just a single lucet_wiggle::lucet_integration! invocation.
Switch lucet-wasi to use tokio
In https://github.com/bytecodealliance/wasmtime/pull/2832 I went to lengths to make give wasmtime-wasi users the option of using plain-old synchronous Rust, or using async Rust on top of tokio. I decided not to do this on Lucet and instead mandate that lucet-wasi users use tokio. My reasons for this are:
Lucet makes it harder to have multiple definitions of import functions than Wasmtime does - you'd have to select whether to use the sync or async tokio definition of a hostcall at AOT compile time via bindings.json
Many production users of Lucet are already running it on top of tokio.
Lucet is approaching EOL - users who need flexibility should switch to wasmtime. All of the features which make wasmtime performance meet or exceed Lucet have landed.
By switching lucet-wasi to use tokio, blocking calls (notably poll_oneoff) interact with the tokio executor correctly - a poll_oneoff waiting on a timer will be implemented by tokio's Timeout future. Other blocking syscalls will use block_in_place to cooperate with the executor. Prior to this change, running lucet-wasi on top of tokio would block the thread without the executor's cooperation, which will almost certainly result in bad behavior.
tldr
Support async in lucet-wiggle
Earlier this year, support for async in wiggle landed in upstream wasmtime in https://github.com/bytecodealliance/wasmtime/pull/2701, and using this async functionality so that wasi-common can operate on tokio landed in https://github.com/bytecodealliance/wasmtime/pull/2832.
This PR ports Lucet to use those new capabilities of wiggle and wasi-common, where the entire host function is an
async fn
executed on the host stack viaVmctx::block_on
. This is a significant departure from the existing Lucet async style of only usingVmctx::block_on
in small sections. However, it is also currently impossible to use the Wiggle module traits as defined by upstreamwasi-common
, because currently Wasmtime does not require async host functions to implSend
, and in fact they close overWasiCtx
which is not safe toSend
.To solve this impedance mismatch, this PR vendors in the changes made to the wiggle and wasi-common family of crates by @alexcrichton in https://github.com/bytecodealliance/wasmtime/pull/2897. These changes transform Wiggle module traits to take
&mut self
rather than&self
, and simplify the structure ofWasiCtx
so that it does now implSend
. So, this version of upstream is compatible with Lucet, but since it is gated behind RFC11 we are vendoring it until it lands. All references to the wiggle{-} and wasi- crates in the Lucet workspace have been changed to paths in thewasmtime-new-api
directory.lucet-wiggle was previously a bit clunky due to constraints in wiggle which went away a while ago. It has been redesigned to work just like wasmtime-wiggle: it re-exports wiggle, and provides its own
lucet_integration!
proc macro which only defines the code which hooks up the code generated fromwiggle::from_witx!
to the lucet runtime. Previously lucet-wiggle shipped its ownfrom_witx!
macro which combined both of those macros into one.That change also meant we can get rid of
lucet-wasi-generate
entirely! No more special proc macro or boilerplate is required for hooking up thewasi-common
definitions directly as Lucet hostcalls - just a singlelucet_wiggle::lucet_integration!
invocation.Switch lucet-wasi to use tokio
In https://github.com/bytecodealliance/wasmtime/pull/2832 I went to lengths to make give wasmtime-wasi users the option of using plain-old synchronous Rust, or using async Rust on top of tokio. I decided not to do this on Lucet and instead mandate that lucet-wasi users use tokio. My reasons for this are:
By switching lucet-wasi to use tokio, blocking calls (notably poll_oneoff) interact with the tokio executor correctly - a poll_oneoff waiting on a timer will be implemented by tokio's Timeout future. Other blocking syscalls will use block_in_place to cooperate with the executor. Prior to this change, running lucet-wasi on top of tokio would block the thread without the executor's cooperation, which will almost certainly result in bad behavior.