std\sys\pal\windows/
futex.rs

1use core::ffi::c_void;
2use core::ptr;
3use core::sync::atomic::{
4    Atomic, AtomicBool, AtomicI8, AtomicI16, AtomicI32, AtomicI64, AtomicIsize, AtomicPtr,
5    AtomicU8, AtomicU16, AtomicU32, AtomicU64, AtomicUsize,
6};
7use core::time::Duration;
8
9use super::api::{self, WinError};
10use crate::sys::{c, dur2timeout};
11
12/// An atomic for use as a futex that is at least 32-bits but may be larger
13pub type Futex = Atomic<Primitive>;
14/// Must be the underlying type of Futex
15pub type Primitive = u32;
16
17/// An atomic for use as a futex that is at least 8-bits but may be larger.
18pub type SmallFutex = Atomic<SmallPrimitive>;
19/// Must be the underlying type of SmallFutex
20pub type SmallPrimitive = u8;
21
22pub unsafe trait Futexable {}
23pub unsafe trait Waitable {
24    type Futex;
25}
26macro_rules! unsafe_waitable_int {
27    ($(($int:ty, $atomic:ty)),*$(,)?) => {
28        $(
29            unsafe impl Waitable for $int {
30                type Futex = $atomic;
31            }
32            unsafe impl Futexable for $atomic {}
33        )*
34    };
35}
36unsafe_waitable_int! {
37    (bool, AtomicBool),
38    (i8, AtomicI8),
39    (i16, AtomicI16),
40    (i32, AtomicI32),
41    (i64, AtomicI64),
42    (isize, AtomicIsize),
43    (u8, AtomicU8),
44    (u16, AtomicU16),
45    (u32, AtomicU32),
46    (u64, AtomicU64),
47    (usize, AtomicUsize),
48}
49unsafe impl<T> Waitable for *const T {
50    type Futex = Atomic<*mut T>;
51}
52unsafe impl<T> Waitable for *mut T {
53    type Futex = Atomic<*mut T>;
54}
55unsafe impl<T> Futexable for AtomicPtr<T> {}
56
57pub fn wait_on_address<W: Waitable>(
58    address: &W::Futex,
59    compare: W,
60    timeout: Option<Duration>,
61) -> bool {
62    unsafe {
63        let addr = ptr::from_ref(address).cast::<c_void>();
64        let size = size_of::<W>();
65        let compare_addr = (&raw const compare).cast::<c_void>();
66        let timeout = timeout.map(dur2timeout).unwrap_or(c::INFINITE);
67        c::WaitOnAddress(addr, compare_addr, size, timeout) == c::TRUE
68    }
69}
70
71pub fn wake_by_address_single<T: Futexable>(address: &T) {
72    unsafe {
73        let addr = ptr::from_ref(address).cast::<c_void>();
74        c::WakeByAddressSingle(addr);
75    }
76}
77
78pub fn wake_by_address_all<T: Futexable>(address: &T) {
79    unsafe {
80        let addr = ptr::from_ref(address).cast::<c_void>();
81        c::WakeByAddressAll(addr);
82    }
83}
84
85pub fn futex_wait<W: Waitable>(futex: &W::Futex, expected: W, timeout: Option<Duration>) -> bool {
86    // return false only on timeout
87    wait_on_address(futex, expected, timeout) || api::get_last_error() != WinError::TIMEOUT
88}
89
90pub fn futex_wake<T: Futexable>(futex: &T) -> bool {
91    wake_by_address_single(futex);
92    false
93}
94
95pub fn futex_wake_all<T: Futexable>(futex: &T) {
96    wake_by_address_all(futex)
97}