parking_lot_core\thread_parker\windows/
waitaddress.rs
1use core::{
9 mem,
10 sync::atomic::{AtomicUsize, Ordering},
11};
12use std::{ffi, time::Instant};
13
14use super::bindings::*;
15
16#[allow(non_snake_case)]
17pub struct WaitAddress {
18 WaitOnAddress: WaitOnAddress,
19 WakeByAddressSingle: WakeByAddressSingle,
20}
21
22impl WaitAddress {
23 #[allow(non_snake_case)]
24 pub fn create() -> Option<WaitAddress> {
25 let synch_dll = unsafe { GetModuleHandleA(b"api-ms-win-core-synch-l1-2-0.dll\0".as_ptr()) };
26 if synch_dll == 0 {
27 return None;
28 }
29
30 let WaitOnAddress = unsafe { GetProcAddress(synch_dll, b"WaitOnAddress\0".as_ptr())? };
31 let WakeByAddressSingle =
32 unsafe { GetProcAddress(synch_dll, b"WakeByAddressSingle\0".as_ptr())? };
33
34 Some(WaitAddress {
35 WaitOnAddress: unsafe { mem::transmute(WaitOnAddress) },
36 WakeByAddressSingle: unsafe { mem::transmute(WakeByAddressSingle) },
37 })
38 }
39
40 #[inline]
41 pub fn prepare_park(&'static self, key: &AtomicUsize) {
42 key.store(1, Ordering::Relaxed);
43 }
44
45 #[inline]
46 pub fn timed_out(&'static self, key: &AtomicUsize) -> bool {
47 key.load(Ordering::Relaxed) != 0
48 }
49
50 #[inline]
51 pub fn park(&'static self, key: &AtomicUsize) {
52 while key.load(Ordering::Acquire) != 0 {
53 let r = self.wait_on_address(key, INFINITE);
54 debug_assert!(r == true.into());
55 }
56 }
57
58 #[inline]
59 pub fn park_until(&'static self, key: &AtomicUsize, timeout: Instant) -> bool {
60 while key.load(Ordering::Acquire) != 0 {
61 let now = Instant::now();
62 if timeout <= now {
63 return false;
64 }
65 let diff = timeout - now;
66 let timeout = diff
67 .as_secs()
68 .checked_mul(1000)
69 .and_then(|x| x.checked_add((diff.subsec_nanos() as u64 + 999999) / 1000000))
70 .map(|ms| {
71 if ms > std::u32::MAX as u64 {
72 INFINITE
73 } else {
74 ms as u32
75 }
76 })
77 .unwrap_or(INFINITE);
78 if self.wait_on_address(key, timeout) == false.into() {
79 debug_assert_eq!(unsafe { GetLastError() }, ERROR_TIMEOUT);
80 }
81 }
82 true
83 }
84
85 #[inline]
86 pub fn unpark_lock(&'static self, key: &AtomicUsize) -> UnparkHandle {
87 key.store(0, Ordering::Release);
89
90 UnparkHandle {
91 key: key,
92 waitaddress: self,
93 }
94 }
95
96 #[inline]
97 fn wait_on_address(&'static self, key: &AtomicUsize, timeout: u32) -> BOOL {
98 let cmp = 1usize;
99 unsafe {
100 (self.WaitOnAddress)(
101 key as *const _ as *mut ffi::c_void,
102 &cmp as *const _ as *mut ffi::c_void,
103 mem::size_of::<usize>(),
104 timeout,
105 )
106 }
107 }
108}
109
110pub struct UnparkHandle {
114 key: *const AtomicUsize,
115 waitaddress: &'static WaitAddress,
116}
117
118impl UnparkHandle {
119 #[inline]
122 pub fn unpark(self) {
123 unsafe { (self.waitaddress.WakeByAddressSingle)(self.key as *mut ffi::c_void) };
124 }
125}