use core::sync::atomic::{AtomicI32, Ordering};
static RWLOCK_STATE: AtomicI32 = AtomicI32::new(0);
#[link(wasm_import_module = "wvl_atomic")]
unsafe extern "C" {
fn __wvl_atomic_wait32_vfs(addr: *const u32, expected: u32, timeout: i64) -> i32;
fn __wvl_atomic_notify_vfs(addr: *const u32, count: u32) -> i32;
}
#[unsafe(no_mangle)]
pub extern "C" fn __wasip1_vfs_memory_lock_read_acquire() {
loop {
let old = RWLOCK_STATE.load(Ordering::Relaxed);
if old >= 0 {
if RWLOCK_STATE
.compare_exchange_weak(old, old + 1, Ordering::Acquire, Ordering::Relaxed)
.is_ok()
{
return;
}
continue;
}
unsafe {
__wvl_atomic_wait32_vfs(
RWLOCK_STATE.as_ptr() as *const u32,
old as u32, -1, );
}
}
}
#[unsafe(no_mangle)]
pub extern "C" fn __wasip1_vfs_memory_lock_read_release() {
let old = RWLOCK_STATE.fetch_sub(1, Ordering::Release);
if old == 1 {
unsafe {
__wvl_atomic_notify_vfs(RWLOCK_STATE.as_ptr() as *const u32, 1);
}
}
}
#[unsafe(no_mangle)]
pub extern "C" fn __wasip1_vfs_memory_lock_write_acquire() {
loop {
match RWLOCK_STATE.compare_exchange_weak(0, -1, Ordering::Acquire, Ordering::Relaxed) {
Ok(_) => return, Err(current) => {
unsafe {
__wvl_atomic_wait32_vfs(
RWLOCK_STATE.as_ptr() as *const u32,
current as u32,
-1,
);
}
}
}
}
}
#[unsafe(no_mangle)]
pub extern "C" fn __wasip1_vfs_memory_lock_write_release() {
RWLOCK_STATE.store(0, Ordering::Release);
unsafe {
__wvl_atomic_notify_vfs(RWLOCK_STATE.as_ptr() as *const u32, u32::MAX);
}
}
pub fn lock_read() -> ReadGuard {
__wasip1_vfs_memory_lock_read_acquire();
ReadGuard(())
}
pub fn lock_write() -> WriteGuard {
__wasip1_vfs_memory_lock_write_acquire();
WriteGuard(())
}
pub struct ReadGuard(());
impl Drop for ReadGuard {
fn drop(&mut self) {
__wasip1_vfs_memory_lock_read_release();
}
}
pub struct WriteGuard(());
impl Drop for WriteGuard {
fn drop(&mut self) {
__wasip1_vfs_memory_lock_write_release();
}
}
crate::gen_alt_global!(vfs_external_memory_manager);
#[link(wasm_import_module = "wasip1-vfs_single_memory")]
unsafe extern "C" {
fn __wasip1_vfs_memory_grow_alt(_: i32) -> i32;
}
#[unsafe(no_mangle)]
extern "C" fn __wasip1_vfs_memory_grow_locker(page_size: i32) -> i32 {
let _guard = lock_write();
unsafe { __wasip1_vfs_memory_grow_alt(page_size) }
}