1
Fork 0

Add Waitable trait

This commit is contained in:
Chris Denton 2024-03-05 18:44:46 +00:00
parent 2a09857729
commit cf83d83c77
No known key found for this signature in database
GPG key ID: 713472F2F45627DE

View file

@ -4,21 +4,58 @@ use crate::sys::dur2timeout;
use core::ffi::c_void; use core::ffi::c_void;
use core::mem; use core::mem;
use core::ptr; use core::ptr;
use core::sync::atomic::{
AtomicBool, AtomicI16, AtomicI32, AtomicI64, AtomicI8, AtomicIsize, AtomicPtr, AtomicU16,
AtomicU32, AtomicU64, AtomicU8, AtomicUsize,
};
use core::time::Duration; use core::time::Duration;
#[inline(always)] pub unsafe trait Waitable {
pub fn wait_on_address<T, U>(address: &T, compare: U, timeout: Option<Duration>) -> bool { type Atomic;
assert_eq!(mem::size_of::<T>(), mem::size_of::<U>()); }
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<T> Waitable for *const T {
type Atomic = AtomicPtr<T>;
}
unsafe impl<T> Waitable for *mut T {
type Atomic = AtomicPtr<T>;
}
pub fn wait_on_address<W: Waitable>(
address: &W::Atomic,
compare: W,
timeout: Option<Duration>,
) -> bool {
unsafe { unsafe {
let addr = ptr::from_ref(address).cast::<c_void>(); let addr = ptr::from_ref(address).cast::<c_void>();
let size = mem::size_of::<T>(); let size = mem::size_of::<W>();
let compare_addr = ptr::addr_of!(compare).cast::<c_void>(); let compare_addr = ptr::addr_of!(compare).cast::<c_void>();
let timeout = timeout.map(dur2timeout).unwrap_or(c::INFINITE); let timeout = timeout.map(dur2timeout).unwrap_or(c::INFINITE);
c::WaitOnAddress(addr, compare_addr, size, timeout) == c::TRUE c::WaitOnAddress(addr, compare_addr, size, timeout) == c::TRUE
} }
} }
#[inline(always)]
pub fn wake_by_address_single<T>(address: &T) { pub fn wake_by_address_single<T>(address: &T) {
unsafe { unsafe {
let addr = ptr::from_ref(address).cast::<c_void>(); let addr = ptr::from_ref(address).cast::<c_void>();
@ -26,7 +63,6 @@ pub fn wake_by_address_single<T>(address: &T) {
} }
} }
#[inline(always)]
pub fn wake_by_address_all<T>(address: &T) { pub fn wake_by_address_all<T>(address: &T) {
unsafe { unsafe {
let addr = ptr::from_ref(address).cast::<c_void>(); let addr = ptr::from_ref(address).cast::<c_void>();
@ -34,19 +70,16 @@ pub fn wake_by_address_all<T>(address: &T) {
} }
} }
#[inline(always)] pub fn futex_wait<W: Waitable>(futex: &W::Atomic, expected: W, timeout: Option<Duration>) -> bool {
pub fn futex_wait<T, U>(futex: &T, expected: U, timeout: Option<Duration>) -> bool {
// return false only on timeout // return false only on timeout
wait_on_address(futex, expected, timeout) || api::get_last_error().code != c::ERROR_TIMEOUT wait_on_address(futex, expected, timeout) || api::get_last_error().code != c::ERROR_TIMEOUT
} }
#[inline(always)]
pub fn futex_wake<T>(futex: &T) -> bool { pub fn futex_wake<T>(futex: &T) -> bool {
wake_by_address_single(futex); wake_by_address_single(futex);
false false
} }
#[inline(always)]
pub fn futex_wake_all<T>(futex: &T) { pub fn futex_wake_all<T>(futex: &T) {
wake_by_address_all(futex) wake_by_address_all(futex)
} }