use super::api; use crate::sys::c; use crate::sys::dur2timeout; use core::ffi::c_void; use core::mem; use core::ptr; use core::sync::atomic::{ AtomicBool, AtomicI16, AtomicI32, AtomicI64, AtomicI8, AtomicIsize, AtomicPtr, AtomicU16, AtomicU32, AtomicU64, AtomicU8, AtomicUsize, }; use core::time::Duration; pub unsafe trait Waitable { type Atomic; } macro_rules! unsafe_waitable_int { ($(($int:ty, $atomic:ty)),*$(,)?) => { $( unsafe impl Waitable for $int { type Atomic = $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 Atomic = AtomicPtr; } unsafe impl Waitable for *mut T { type Atomic = AtomicPtr; } pub fn wait_on_address( address: &W::Atomic, compare: W, timeout: Option, ) -> bool { unsafe { let addr = ptr::from_ref(address).cast::(); let size = mem::size_of::(); let compare_addr = ptr::addr_of!(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::Atomic, expected: W, timeout: Option) -> bool { // return false only on timeout wait_on_address(futex, expected, timeout) || api::get_last_error().code != c::ERROR_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) }