Hi all,
As I find myself working on a PoC embedding wasmtime in a large C application, I have a few questions which the documentation seems to not answer (it appears that the "C embedding" use-case isn't quite well documented yet). I hope that it's fine to ask for a few clarifications here (topics touch both WASI and wasmtime, so I am posting in this channel).
My use-case is to lookup for entrypoints/hooks in the compiled wasm module (e.g. init
and exit
"hooks"), and, if they are defined, call those at given points in the lifetime of the C application.
The few points on which I am eager for clarifications for now are:
Is there a better way to lookup for exported symbols other than looping over wasm_exporttype_vec_t
? Most of the C examples export a single symbol _or_ simply invoke _start
, but these examples seem rather simplistic. For now, I have: for (i=0; i<wasm_exports.size;i++) { /* get wasm_name_t* */ if (strncmp(wasm_name->data, "init", wasm_name->size)) { /* ... */ } }
. However that seems a little contrived compared to the Rust interface which supports a more elegant and efficient instance.get_func("init")
.
As far as I can tell, only the threads.c
example from wasm-c-api touches on the topic of multi-threaded applications, and how modules/instances should be created and managed. In my case, my application is single-threaded and uses non-blocking (event-driven) I/O.
a. In this case, how should I organize my wasm stores/modules/instances? Can each green-thread reuse the same instance? Modules? Stores? My thinking for the time being is to have all green threads share the same wasm_module_t
, but to have each of them create their own wasm_instance_t
.
b. What if each green-thread reuses the same wasm_instance_t
? Can I expect each call to wasmtime_func_call()
to have its own stack frame? This way, all green-threads would execute on their own stack, but could share global variables?
c. And finally, is it fine for the wasm_store_t
to be shared between green-threads? Do stores only come in play when security concerns enter the picture?
When using WASI, do each of my wasm_instance_t
need their own wasi_instance_t
, or can all wasm_instance_t
share the same wasi_instance_t
? I assume the former, but am hoping for confirmation.
Given that my C application implements event-driven I/O (i.e. epoll
), does wasmtime have some sort of support for yielding from calls and resuming? I.e. suspend the WASM execution until some I/O finishes. If not, is such support planned in the future?
And finally, is there a place in the documentation that better describe the role fulfilled by the stores/modules/instances/wasi instances as well as their cost? Did I miss it?
Since my C embedding use-case seems fairly typical and somewhat large in scope, I'd be happy to help out improving the wasmtime C embedding experience as well; mostly hoping to get more familiar with it for the time being.
That's it for now, TIA to folks who will spend some time reading these!
This topic was moved here from #general > Clarifications around a C embedding use-case by Till Schneidereit
Hi @Thibault Charbonnier, it's definitely very much fine to ask these questions here—that's one of the reasons we have this Zulip for! :slight_smile:
I moved the conversation over to the #wasmtime stream so some more folks working on Wasmtime might see it. Unfortunately I'm not the right person to answer your questions, though :frown: @Yury Delendik and @Alex Crichton might be able to answer at least some.
re:1. wasm-c-api has no "symbol look up by name"-method -- what you did is how https://github.com/WebAssembly/wasm-c-api/ is assuming users will do
re:2. as you can see at https://github.com/WebAssembly/wasm-c-api/blob/master/example/threads.c, new store is created for different thread, module needs to "obtained" at different thread by its store (not sure if we implemented wasm_module_share / _obtain in the wasmtime yet), and then create one or more instances on the same thread
notice that wasm_module_share or wasm_module_obtain, if not present, can be replaced by repetitive wasm_module_new for different stores (at will be slower than intended by design)
re:3. linking is happening at externals/exports level, one or more instances (imports) can be linked with other instances export(s) from the same store. it will be no different in WASI context.
re: 5. the https://github.com/WebAssembly/wasm-c-api/ was our resource in implementing C API. We have our documentation for Rust API at https://docs.rs/wasmtime/0.16.0/wasmtime/ -- it might help with reading C API (though it is our interpretation).
one thing I'd add on (1) is that we haven't focused too much yet on the ergonomics of the C API. Currently we've focused on implementing the proposed standard as well as whatever is necessary to implement our language extensions safely. We already have a wasmtime-specific wasmtime.h
, however, and we'd be happy to add extensions there which make things more ergonomic
for (2) I would add that threading is not yet implemented in wasmtime, so all structures except wasm_engine_t
and wasm_config_t
must be single-threaded. You can't share stores and below across threads. If all the green threads are pinned to the same OS thread then yes, they can share instances/modules/stores/etc.
for (4) wasmtime does not yet support async host calls which can yield back to the host. It's something we're interested in exploring, however! We had a contributor create the wasmtime-async
crate recently which shows one strategy of doing so (stack switching), but it may not be appropriate for all use cases
I'd add to (5) that the documentation of when to use a Store
(or wasm_store_t
) is probably pretty lacking. I think it's something we can definitely improve on. As Yury mentioned the proposed standard API has very little documentation, so we're on our own to make it!
Thank you to all of you for your answers
Last updated: Dec 23 2024 at 13:07 UTC