Apologies, accidentally put this in the wrong channel:
Hi there. I'm currently writing a WASM interface using Wasmtime wherein the host has a function that will:
- read message bytes from the WASM module's memory
spawn a future that will:
a. action the message represented by those bytes
b. write some bytes to the WASM module's memory in response
c. call a WASM export to notify the module of completionreturn (before the future has completed)
However the problem is that writing to memory requires a context, and we can't use the caller's context as that is only valid for the lifetime of the original host function call. What should I use instead? Thanks.
How are you preventing the wasm export from being called by the future while code in the wasm module is already running? You can't enter wasm instances from multiple threads.
Yeah I hadn't thought of that. I did some more looking around and it feels like what I want is to wrap the store in a mutex, which will also guarantee single access.
Obviously that'll deadlock where I've got access to the caller, so I've essentially done something like:
enum PluginFunctionsWasmInterface<'a, H: crate::Contract> {
Caller {
caller: wasmtime::Caller<'a, crate::Address<H>>,
store: SharedStore<H>,
},
Store(&'a mut wasmtime::Store<crate::Address<H>>),
}
impl<'a, H: crate::Contract> wasmtime::AsContext for PluginFunctionsWasmInterface<'a, H> {
type Data = crate::Address<H>;
fn as_context(&self) -> wasmtime::StoreContext<'_, Self::Data> {
match self {
Self::Caller { caller, .. } => caller.as_context(),
Self::Store(store) => store.as_context(),
}
}
}
impl<'a, H: crate::Contract> wasmtime::AsContextMut for PluginFunctionsWasmInterface<'a, H> {
fn as_context_mut(&mut self) -> wasmtime::StoreContextMut<'_, Self::Data> {
match self {
Self::Caller { caller, .. } => caller.as_context_mut(),
Self::Store(store) => store.as_context_mut(),
}
}
}
I don't believe Wasmtime has utilities at this time to help you here and this'll be a Rust/embedding problem you'll have to solve
Yeah... I was secretly hoping that wasmtime didn't care/had as much knowledge of threads as WASM itself does (obviously ignoring the WASM threading proposal) but I guess this is sensible from a host perspective as well. For now I'll just deal with my accesses to the WASM module being serialised using that mutex, as that seems to compile at least and there's no obvious deadlocks I can see so long as I use the Caller
when available instead of the mutex-guarded Store
.
Just figured I'd follow up and say I managed to get this working satisfyingly enough :) I did end up using the above solution of "using caller if available, and if not wait until we acquire a mutex to the Store
". I was keen not to have a dedicated OS thread at all times for the plugin (mainly to anticipate having lot of plugins), which is why I wanted to get this working so I could reuse the scheduling done by tokio. As a bonus I also made it so the plugin could spawn futures on the host runtime as well, so lots of fun shenanigans here. Fighting internally to get this open-sourced at some point.
Last updated: Apr 09 2025 at 14:04 UTC