parking_lot_core\thread_parker\windows/
mod.rs1use core::{
9 ptr,
10 sync::atomic::{AtomicPtr, AtomicUsize, Ordering},
11};
12use std::time::Instant;
13
14mod bindings;
15mod keyed_event;
16mod waitaddress;
17
18enum Backend {
19 KeyedEvent(keyed_event::KeyedEvent),
20 WaitAddress(waitaddress::WaitAddress),
21}
22
23static BACKEND: AtomicPtr<Backend> = AtomicPtr::new(ptr::null_mut());
24
25impl Backend {
26 #[inline]
27 fn get() -> &'static Backend {
28 let backend_ptr = BACKEND.load(Ordering::Acquire);
30 if !backend_ptr.is_null() {
31 return unsafe { &*backend_ptr };
32 };
33
34 Backend::create()
35 }
36
37 #[cold]
38 fn create() -> &'static Backend {
39 let backend;
41 if let Some(waitaddress) = waitaddress::WaitAddress::create() {
42 backend = Backend::WaitAddress(waitaddress);
43 } else if let Some(keyed_event) = keyed_event::KeyedEvent::create() {
44 backend = Backend::KeyedEvent(keyed_event);
45 } else {
46 panic!(
47 "parking_lot requires either NT Keyed Events (WinXP+) or \
48 WaitOnAddress/WakeByAddress (Win8+)"
49 );
50 }
51
52 let backend_ptr = Box::into_raw(Box::new(backend));
54 match BACKEND.compare_exchange(
55 ptr::null_mut(),
56 backend_ptr,
57 Ordering::Release,
58 Ordering::Relaxed,
59 ) {
60 Ok(_) => unsafe { &*backend_ptr },
61 Err(global_backend_ptr) => {
62 unsafe {
63 let _ = Box::from_raw(backend_ptr);
65 &*global_backend_ptr
66 }
67 }
68 }
69 }
70}
71
72pub struct ThreadParker {
74 key: AtomicUsize,
75 backend: &'static Backend,
76}
77
78impl super::ThreadParkerT for ThreadParker {
79 type UnparkHandle = UnparkHandle;
80
81 const IS_CHEAP_TO_CONSTRUCT: bool = true;
82
83 #[inline]
84 fn new() -> ThreadParker {
85 ThreadParker {
89 key: AtomicUsize::new(0),
90 backend: Backend::get(),
91 }
92 }
93
94 #[inline]
96 unsafe fn prepare_park(&self) {
97 match *self.backend {
98 Backend::KeyedEvent(ref x) => x.prepare_park(&self.key),
99 Backend::WaitAddress(ref x) => x.prepare_park(&self.key),
100 }
101 }
102
103 #[inline]
106 unsafe fn timed_out(&self) -> bool {
107 match *self.backend {
108 Backend::KeyedEvent(ref x) => x.timed_out(&self.key),
109 Backend::WaitAddress(ref x) => x.timed_out(&self.key),
110 }
111 }
112
113 #[inline]
116 unsafe fn park(&self) {
117 match *self.backend {
118 Backend::KeyedEvent(ref x) => x.park(&self.key),
119 Backend::WaitAddress(ref x) => x.park(&self.key),
120 }
121 }
122
123 #[inline]
127 unsafe fn park_until(&self, timeout: Instant) -> bool {
128 match *self.backend {
129 Backend::KeyedEvent(ref x) => x.park_until(&self.key, timeout),
130 Backend::WaitAddress(ref x) => x.park_until(&self.key, timeout),
131 }
132 }
133
134 #[inline]
138 unsafe fn unpark_lock(&self) -> UnparkHandle {
139 match *self.backend {
140 Backend::KeyedEvent(ref x) => UnparkHandle::KeyedEvent(x.unpark_lock(&self.key)),
141 Backend::WaitAddress(ref x) => UnparkHandle::WaitAddress(x.unpark_lock(&self.key)),
142 }
143 }
144}
145
146pub enum UnparkHandle {
150 KeyedEvent(keyed_event::UnparkHandle),
151 WaitAddress(waitaddress::UnparkHandle),
152}
153
154impl super::UnparkHandleT for UnparkHandle {
155 #[inline]
158 unsafe fn unpark(self) {
159 match self {
160 UnparkHandle::KeyedEvent(x) => x.unpark(),
161 UnparkHandle::WaitAddress(x) => x.unpark(),
162 }
163 }
164}
165
166#[inline]
168pub fn thread_yield() {
169 unsafe {
170 bindings::Sleep(0);
174 }
175}