shared_rwlock\sys\windows/
futex.rs1mod c {
8 use windows::Win32::Foundation::GetLastError;
9 pub use windows::Win32::System::Threading::{
10 WaitOnAddress, WakeByAddressAll, WakeByAddressSingle, INFINITE,
11 };
12
13 use std::time::Duration;
14
15 pub fn dur2timeout(dur: Duration) -> u32 {
16 dur.as_secs()
24 .checked_mul(1000)
25 .and_then(|ms| ms.checked_add((dur.subsec_nanos() as u64) / 1_000_000))
26 .and_then(|ms| {
27 ms.checked_add(if dur.subsec_nanos() % 1_000_000 > 0 {
28 1
29 } else {
30 0
31 })
32 })
33 .map_or(INFINITE, |ms| {
34 if ms > <u32>::MAX as u64 {
35 INFINITE
36 } else {
37 ms as u32
38 }
39 })
40 }
41
42 pub fn get_last_error() -> u32 {
46 unsafe { GetLastError().0 }
48 }
49
50 pub const TIMEOUT: u32 = 1460;
51}
52
53use core::ffi::c_void;
54use core::sync::atomic::{
55 AtomicBool, AtomicI16, AtomicI32, AtomicI64, AtomicI8, AtomicIsize, AtomicPtr, AtomicU16,
56 AtomicU32, AtomicU64, AtomicU8, AtomicUsize,
57};
58use core::time::Duration;
59use core::{mem, ptr};
60
61use c::dur2timeout;
62
63pub type Futex = AtomicU32;
65pub type Primitive = u32;
67
68pub unsafe trait Futexable {}
71pub unsafe trait Waitable {
74 type Futex;
75}
76macro_rules! unsafe_waitable_int {
77 ($(($int:ty, $atomic:ty)),*$(,)?) => {
78 $(
79 unsafe impl Waitable for $int {
80 type Futex = $atomic;
81 }
82 unsafe impl Futexable for $atomic {}
83 )*
84 };
85}
86unsafe_waitable_int! {
87 (bool, AtomicBool),
88 (i8, AtomicI8),
89 (i16, AtomicI16),
90 (i32, AtomicI32),
91 (i64, AtomicI64),
92 (isize, AtomicIsize),
93 (u8, AtomicU8),
94 (u16, AtomicU16),
95 (u32, AtomicU32),
96 (u64, AtomicU64),
97 (usize, AtomicUsize),
98}
99unsafe impl<T> Waitable for *const T {
100 type Futex = AtomicPtr<T>;
101}
102unsafe impl<T> Waitable for *mut T {
103 type Futex = AtomicPtr<T>;
104}
105unsafe impl<T> Futexable for AtomicPtr<T> {}
106
107pub fn wait_on_address<W: Waitable>(
108 address: &W::Futex,
109 compare: W,
110 timeout: Option<Duration>,
111) -> bool {
112 unsafe {
113 let addr = ptr::from_ref(address).cast::<c_void>();
114 let size = mem::size_of::<W>();
115 let compare_addr = (&raw const compare).cast::<c_void>();
116 let timeout = timeout.map_or(c::INFINITE, dur2timeout);
117 c::WaitOnAddress(addr, compare_addr, size, Some(timeout)).is_ok()
118 }
119}
120
121pub fn wake_by_address_single<T: Futexable>(address: &T) {
122 unsafe {
123 let addr = ptr::from_ref(address).cast::<c_void>();
124 c::WakeByAddressSingle(addr);
125 }
126}
127
128pub fn wake_by_address_all<T: Futexable>(address: &T) {
129 unsafe {
130 let addr = ptr::from_ref(address).cast::<c_void>();
131 c::WakeByAddressAll(addr);
132 }
133}
134
135pub fn futex_wait<W: Waitable>(futex: &W::Futex, expected: W, timeout: Option<Duration>) -> bool {
136 wait_on_address(futex, expected, timeout) || c::get_last_error() != c::TIMEOUT
138}
139
140pub fn futex_wake<T: Futexable>(futex: &T) -> bool {
141 wake_by_address_single(futex);
142 false
143}
144
145pub fn futex_wake_all<T: Futexable>(futex: &T) {
146 wake_by_address_all(futex);
147}