blob: b83e75acac3ae22fd6812b75509f1fc682fec52f [file] [edit]
//! A futex implementation based on the primitives provided by `wasi-libc`.
//!
//! This is currently only used on wasip3 targets, but in the future once
//! `wasi-libc`'s implementation of these symbols have percolated further it'll
//! be possible to use this on all WASI targets. The `wasi-libc` implementation
//! of these symbols differs depending on the target and configuration:
//!
//! * `wasm32-wasip{1,2}` - this will abort if blocking actually happens
//! * `wasm32-wasip1-threads` - this uses wasm `memory.atomic.*` instructions
//! * `wasm32-wasip3` - depending on libc configuration (`ENABLE_COOP_THREADS`)
//! this either aborts (coop threads disables) on blocking or does the
//! coop-thread-thing to manage threads.
//!
//! Regardless this module is effectively delegating to `wasi-libc` to determine
//! how to do thread management.
use libc::c_int;
use crate::ptr;
use crate::sync::atomic::Atomic;
use crate::time::Duration;
const __WASILIBC_FUTEX_WAKE_ALL: c_int = -1;
unsafe extern "C" {
fn __wasilibc_futex_wait(
addr: *mut c_int,
val: c_int,
clock: libc::clockid_t,
at: *const libc::timespec,
flags: libc::c_uint,
) -> c_int;
fn __wasilibc_futex_wake(addr: *const c_int, count: c_int, flags: libc::c_uint) -> c_int;
}
pub type Futex = Atomic<Primitive>;
pub type Primitive = u32;
pub type SmallFutex = Atomic<SmallPrimitive>;
pub type SmallPrimitive = u32;
pub fn futex_wait(futex: &Atomic<u32>, expected: u32, timeout: Option<Duration>) -> bool {
let timespec = timeout.and_then(|t| {
Some(libc::timespec {
tv_sec: t.as_secs().try_into().ok()?,
tv_nsec: t.subsec_nanos().try_into().ok()?,
})
});
unsafe {
__wasilibc_futex_wait(
futex.as_ptr().cast(),
expected.cast_signed(),
libc::CLOCK_REALTIME,
timespec.as_ref().map(ptr::from_ref).unwrap_or(ptr::null()),
0,
) == 0
}
}
pub fn futex_wake(futex: &Atomic<u32>) -> bool {
unsafe { __wasilibc_futex_wake(futex.as_ptr().cast(), 1, 0) == 1 }
}
pub fn futex_wake_all(futex: &Atomic<u32>) {
unsafe {
__wasilibc_futex_wake(futex.as_ptr().cast(), __WASILIBC_FUTEX_WAKE_ALL, 0);
}
}