use std::{mem, ptr, slice};
use anyhow::{anyhow, Result};
use wasi::{Event, EventFdReadwrite, Subscription};
use wasmtime::{Caller, Linker};
pub fn replace_scheduling_functions<T>(linker: &mut Linker<T>) -> Result<()>
where
T: Send,
{
override_scheduling_functions(linker, "wasi_snapshot_preview1")
}
pub fn replace_scheduling_functions_for_wasi_preview_0<T>(linker: &mut Linker<T>) -> Result<()>
where
T: Send,
{
override_scheduling_functions(linker, "wasi_unstable")
}
fn override_scheduling_functions<T>(linker: &mut Linker<T>, module: &str) -> Result<()> {
linker.allow_shadowing(true);
linker.func_wrap(
module,
"poll_oneoff",
|mut caller: Caller<'_, T>,
in_ptr: i32,
out_ptr: i32,
nsubscriptions: i32,
nevents_ptr: i32|
-> anyhow::Result<i32> {
let in_ptr = in_ptr as usize;
let out_ptr = out_ptr as usize;
let nsubscriptions = nsubscriptions as usize;
let nevents_ptr = nevents_ptr as usize;
let memory = caller
.get_export("memory")
.map_or_else(|| Err(anyhow!("missing required memory export")), Ok)?
.into_memory()
.map_or_else(|| Err(anyhow!("missing required memory export")), Ok)?;
for i in 0..nsubscriptions {
let offset = in_ptr + (i * mem::size_of::<Subscription>());
let mut subscription_buffer = [0u8; mem::size_of::<Subscription>()];
memory.read(&caller, offset, &mut subscription_buffer)?;
let subscription =
unsafe { ptr::read(subscription_buffer.as_ptr() as *const Subscription) };
let event = Event {
userdata: subscription.userdata,
error: wasi::ERRNO_SUCCESS,
type_: match subscription.u.tag {
0 => wasi::EVENTTYPE_CLOCK,
1 => wasi::EVENTTYPE_FD_READ,
2 => wasi::EVENTTYPE_FD_WRITE,
_ => unreachable!(),
},
fd_readwrite: EventFdReadwrite {
nbytes: 0,
flags: 0,
},
};
let offset = out_ptr + (i * mem::size_of::<Event>());
let event_buffer = unsafe {
slice::from_raw_parts(
&event as *const Event as *const u8,
mem::size_of::<Event>(),
)
};
memory.write(&mut caller, offset, event_buffer)?
}
let buffer = nsubscriptions.to_le_bytes();
memory.write(&mut caller, nevents_ptr, &buffer)?;
Ok(wasi::ERRNO_SUCCESS.raw() as i32)
},
)?;
linker.func_wrap(module, "sched_yield", || wasi::ERRNO_SUCCESS.raw() as i32)?;
Ok(())
}