Skip to content

Commit

Permalink
Add Waitable trait
Browse files Browse the repository at this point in the history
  • Loading branch information
ChrisDenton committed Mar 5, 2024
1 parent 2a09857 commit 25628ef
Showing 1 changed file with 44 additions and 10 deletions.
54 changes: 44 additions & 10 deletions library/std/src/sys/pal/windows/futex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,49 +4,83 @@ 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;

#[inline(always)]
pub fn wait_on_address<T, U>(address: &T, compare: U, timeout: Option<Duration>) -> bool {
assert_eq!(mem::size_of::<T>(), mem::size_of::<U>());
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<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 {
assert_eq!(mem::size_of::<W>(), mem::size_of::<W>());
unsafe {
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 timeout = timeout.map(dur2timeout).unwrap_or(c::INFINITE);
c::WaitOnAddress(addr, compare_addr, size, timeout) == c::TRUE
}
}

#[inline(always)]
pub fn wake_by_address_single<T>(address: &T) {
unsafe {
let addr = ptr::from_ref(address).cast::<c_void>();
c::WakeByAddressSingle(addr);
}
}

#[inline(always)]
pub fn wake_by_address_all<T>(address: &T) {
unsafe {
let addr = ptr::from_ref(address).cast::<c_void>();
c::WakeByAddressAll(addr);
}
}

#[inline(always)]
pub fn futex_wait<T, U>(futex: &T, expected: U, timeout: Option<Duration>) -> bool {
pub fn futex_wait<W: Waitable>(futex: &W::Atomic, expected: W, timeout: Option<Duration>) -> bool {
// return false only on 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 {
wake_by_address_single(futex);
false
}

#[inline(always)]
pub fn futex_wake_all<T>(futex: &T) {
wake_by_address_all(futex)
}

0 comments on commit 25628ef

Please sign in to comment.