use core::ffi::c_void; use core::ptr; use core::sync::atomic::{ Atomic, AtomicBool, AtomicI8, AtomicI16, AtomicI32, AtomicI64, AtomicIsize, AtomicPtr, AtomicU8, AtomicU16, AtomicU32, AtomicU64, AtomicUsize, }; use core::time::Duration; use super::api::{self, WinError}; use crate::sys::{c, dur2timeout}; /// An atomic for use as a futex that is at least 32-bits but may be larger pub type Futex = Atomic; /// Must be the underlying type of Futex pub type Primitive = u32; /// An atomic for use as a futex that is at least 8-bits but may be larger. pub type SmallFutex = Atomic; /// Must be the underlying type of SmallFutex pub type SmallPrimitive = u8; pub unsafe trait Futexable {} pub unsafe trait Waitable { type Futex; } macro_rules! unsafe_waitable_int { ($(($int:ty, $atomic:ty)),*$(,)?) => { $( unsafe impl Waitable for $int { type Futex = $atomic; } unsafe impl Futexable for $atomic {} )* }; } unsafe_waitable_int! { (bool, AtomicBool), (i8, AtomicI8), (i16, AtomicI16), (i32, AtomicI32), (i64, AtomicI64), (isize, AtomicIsize), (u8, AtomicU8), (u16, AtomicU16), (u32, AtomicU32), (u64, AtomicU64), (usize, AtomicUsize), } unsafe impl Waitable for *const T { type Futex = Atomic<*mut T>; } unsafe impl Waitable for *mut T { type Futex = Atomic<*mut T>; } unsafe impl Futexable for AtomicPtr {} pub fn wait_on_address( address: &W::Futex, compare: W, timeout: Option, ) -> bool { unsafe { let addr = ptr::from_ref(address).cast::(); let size = size_of::(); let compare_addr = (&raw const compare).cast::(); let timeout = timeout.map(dur2timeout).unwrap_or(c::INFINITE); c::WaitOnAddress(addr, compare_addr, size, timeout) == c::TRUE } } pub fn wake_by_address_single(address: &T) { unsafe { let addr = ptr::from_ref(address).cast::(); c::WakeByAddressSingle(addr); } } pub fn wake_by_address_all(address: &T) { unsafe { let addr = ptr::from_ref(address).cast::(); c::WakeByAddressAll(addr); } } pub fn futex_wait(futex: &W::Futex, expected: W, timeout: Option) -> bool { // return false only on timeout wait_on_address(futex, expected, timeout) || api::get_last_error() != WinError::TIMEOUT } pub fn futex_wake(futex: &T) -> bool { wake_by_address_single(futex); false } pub fn futex_wake_all(futex: &T) { wake_by_address_all(futex) }