WASI
WASI copied to clipboard
Alternative to a "conventional" poll api?
Take this issue with a grain-of-salt.
I've noticed that the current (I understand it's a work in progress) wasi api for polling is similar to modern epoll in many ways. Perhaps, implementations that use wasi's polling api (which will presumably be many/most of them) would be simpler if we adopted a simpler, easier to write against api that mirrors that of rust's futures.
I propose that we export a function called register_callback to modules that has the following signature:
(type $t6 (func (param i32 i64 i32) (result i32)))
In rust, that would be:
extern {
fn register_callback(handle: u32, key: u64, f: extern fn(u64)) -> u32;
}
There would be supporting machinery around it, but essentially, you'd register an event--on a socket for instance--to this handle value, and then register a callback associated with it. The key parameter is passed, unchanged, to the callback when the event occurs.
The callback would, at the wasm level, be the index of an exported function.
I think this would integrate quite directly with rust's Futures and other languages' async internals, though I haven't tried it of course. Plus, it would likely reduce the amount of async machinery a module would have to carry around with it by a very significant amount.
There's an important unanswered question: Would this callback be called on a separate thread by the runtime (sort of like a signal), meaning that it would have to use atomic instructions to interface with the module's memory, or would the module have to relinquish control to the runtime for the callbacks to start being called in a single-threaded manner?
I think making it be on another thread limits implementations, and making it on the same thread eventually becomes something like epoll once you generalize it enough, and of course epoll can be expanded to multiple threads. You can also look at something like libuv, which is somewhat similar, although it's tuned for a specific purpose.
I too wondered about this. @lachlansneff do you know of any previous or further discussion around this online or in the meetings?
@jayphelps, I haven't been involved in the wasm community in quite some time, so I'm not aware of any prior discussions of this.
I've worked fairly extensively with callback-based interfaces, and on balance I'd greatly prefer poll-style interfaces. You can easily build callbacks atop poll as a helper library / event-loop library; I don't think the baseline WASI syscalls should inherently use a callback-based interface, though.
Something that I've noticed in general: How does WASI even deal with blocking APIs anyway? Isn't WASI meant to work in the browser where you simply can't block the thread at all? So can something like poll even work?
At this moment in time, all WASI syscalls are blocking. We do want to support async though, and there are many ideas about how to do this.
Callback-style async has some advantages. It puts the event loop in the engine, so that in environments where there's already an event loop (eg. browser main thread, Arduino, and other things), wasm can integrate with it. It also means that wasm can be completely off the stack between events, making it very simple and cheap for engines to switch stacks, suspend/resume, switch JIT tiers, find GC roots, or other things.
Poll-style async also has advantages -- it makes it straightforward to nest async work within synchronous contexts.
Another style is to continue to use a synchronous-style API, and add support for stack switching underneath to allow other code to run while I/O is happening.
It is plausible that WASI overall will support multiple models, or a combination.
Async (disregarding whether callback- or poll- or whatever based) was very thoroughly researched by Microsoft some years ago. They've written a whole new OS using this style (i.e. no preemption, but purely async) - see the series http://joeduffyblog.com/2015/11/19/asynchronous-everything/ . But guess what, it's by far not a silver bullet and the disadvantages outweight advantages. So lessons learned is that languages/APIs have to support both sync/preemptive as well as async (and both comparably well).
It is plausible that WASI overall will support multiple models
I'm raising my hand for this.
It's easy enough to build a callback model atop a pool/select/epoll model. And many applications already have their own event loop, or run atop a language/runtime that has one.
On December 13, 2019 12:39:01 PM PST, Dan Gohman [email protected] wrote:
At this moment in time, all WASI syscalls are blocking. We do want to support async though, and there are many ideas about how to do this.
Callback-style async has some advantages. It puts the event loop in the engine, so that in environments where there's already an event loop (eg. browser main thread, Arduino, and other things), wasm can integrate with it. It also means that wasm can be completely off the stack between events, making it very simple and cheap for engines to switch stacks, suspend/resume, switch JIT tiers, find GC roots, or other things.
Poll-style async also has advantages -- it makes it straightforward to nest async work within synchronous contexts.
Another style is to continue to use a synchronous-style API, and add support for stack switching underneath to allow other code to run while I/O is happening.
It is plausible that WASI overall will support multiple models, or a combination.
It's easy enough to build a callback model atop a pool/select/epoll model. And many applications already have their own event loop, or run atop a language/runtime that has one.
But is converse true? (i.e. can you always build a polling system on top of callback system? ). Sometime building polling mechanism on top a callback system can break the semantics. Imagine, for example, a keyboard event callback system that requires the user code to decide it the event is to be handled before the callback returns. Its not possible to stash such an event in queue and handle it later. It has to be handled synchronously.
a keyboard event callback system that requires the user code to decide it the event is to be handled before the callback returns
Couldn't the callback just call some user code?
a keyboard event callback system that requires the user code to decide it the event is to be handled before the callback returns
Couldn't the callback just call some user code?
In a synchronous event model yes, but not if the user code in question is polling for events.
It seems like quite an oversight to not have a callback based api, especially given that the main use case for wasm is the browser, and threads have never really been a part of that. (single threaded processes with message passing, yes)
There are things like shared array buffers, but it's not supported as widely as wasm is.
Also, single threaded processes and message passing is an excellent model (look at erlang) so it's a shame to miss that when everything was already there ready to go.
Why did this get closed? Is this resolved, if so where?
@CryZe I'm about to open a new issue that presents a new solution to this problem.
As an update here, WebAssembly CG has recently launched a stack-switching subgroup to pursue language-level approaches here.