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!
I don't have all the answers at the moment, but I do have two quick observations:
sched_yield
is about thread/process yielding and not about async yielding, so it isn't going to help here.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.
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.
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:
Philpax has marked this topic as resolved.
Last updated: Nov 22 2024 at 16:03 UTC