| //! 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); | |
| } | |
| } |