Stream: wasmtime

Topic: ✔ Interruptible / guest yielding execution


view this post on Zulip Philpax (Jul 21 2022 at 19:08):

Hi there! I'm experimenting with building a scripting environment with Wasmtime / wit-bindgen and (currently) a Rust guest. For the guest, I'd like to provide an asynchronous environment, like Lua coroutines, so that something like this is possible:

async fn on_player_main_action(id: EntityId) {
    for _ in 0..4 {
        entity_play_sound(id, "Shoot");
        sleep_seconds(0.4).await;
    }
}

I've currently implemented this by modifying the guest's memory to provide it with information about the event when an event occurs, and then I (want to) resume execution of the wasm until all events have been processed.

To do this, I've set up my own (very basic) async runtime that does something like this:

#[no_mangle]
pub extern "C" fn run() {
    let mut futures: Vec<Pin<Box<dyn Future<Output = ()>>>> = vec![];
    let waker = unsafe { Waker::from_raw(RawWaker::new(std::ptr::null(), &RAW_WAKER)) };

    loop {
        let reactor = unsafe { &mut EVENT_REACTOR };
        while let Some(event) = reactor.get() {
            futures.push(/* process event */);
        }

        futures.retain_mut(|f| f.as_mut().poll(&mut Context::from_waker(&waker)) == Poll::Pending);
    }
}

I have three questions regarding this:
0) Will this actually work? Can I have the client manage its own async loop, yield when it's done with all of its events, and have the host resume execution of the loop each time I have an event?
1) How can I make the guest loop yield after it's done processing the events? I've tried wasi::sched_yield(), but that doesn't seem to do anything, but I'm not sure if that's because...
2) How do I actually resume execution of the run function after it yields? Calling it with .call results it in never terminating, and I've not tried .call_async yet as I haven't set up the machinery for polling / making all of the calls asynchronous.

Any help y'all can provide would be much appreciated!

view this post on Zulip Dan Gohman (Jul 21 2022 at 19:13):

I don't have all the answers at the moment, but I do have two quick observations:

Component Model async support proposal WebAssembly CG May/June, 2022

view this post on Zulip Philpax (Jul 21 2022 at 19:19):

Ah, thank you! Appreciate the clarification on sched_yield (could potentially bodge something with epoch interruption?) and the link to the proposal, I'll have to give that a good read over and get familiar with it.

view this post on Zulip Dan Gohman (Jul 21 2022 at 19:25):

Yeah, in theory an engine could bodge sched_yield into serving this purpose, but I don't believe any engines do that today, and stack switching is expected to be what they'll do in the future.

A repository for the stack switching proposal. Contribute to WebAssembly/stack-switching development by creating an account on GitHub.

view this post on Zulip Philpax (Jul 21 2022 at 19:32):

Hmm, I just realised that I don't necessarily need a resumable run if I rearrange my guest-side glue code so that the host calls a function each time to process the events. I'll have to play around with that soon :fingers_crossed:

view this post on Zulip Notification Bot (Jul 22 2022 at 18:05):

Philpax has marked this topic as resolved.


Last updated: Dec 23 2024 at 14:03 UTC