1use std::marker::PhantomData;
2use std::mem::ManuallyDrop;
3use std::ptr::NonNull;
4use std::task::{RawWaker, RawWakerVTable, Waker};
5use std::{fmt, rc::Rc};
6
7use crate::rt::task;
8
9const NATIVE: NonNull<()> = NonNull::dangling();
11const _: () = assert!(align_of::<RawWakerVTable>() > 1);
12
13#[repr(C)]
49pub struct LocalWaker {
50 data: *const (),
51 metadata: NonNull<()>,
53 _local: PhantomData<Rc<()>>,
54}
55
56#[cfg(target_pointer_width = "64")]
57const _: () = {
58 assert!(size_of::<LocalWaker>() == 16);
59 assert!(size_of::<Option<LocalWaker>>() == 16);
60};
61
62impl LocalWaker {
63 #[inline]
65 pub fn from_waker(waker: &Waker) -> Self {
66 if let Some(ptr) = task::local_waker_ptr(waker) {
67 unsafe { task::clone_local_waker(ptr) };
68 Self::native(ptr)
69 } else {
70 Self::fallback(waker.clone())
71 }
72 }
73
74 #[inline]
76 pub fn wake(self) {
77 if self.is_native() {
78 let this = ManuallyDrop::new(self);
79 unsafe { task::wake_local_waker(this.data, true) };
80 } else {
81 self.into_waker().wake();
82 }
83 }
84
85 #[inline]
87 pub fn wake_by_ref(&self) {
88 if self.is_native() {
89 unsafe { task::wake_local_waker(self.data, false) };
90 } else {
91 self.borrowed_waker().wake_by_ref();
92 }
93 }
94
95 #[inline]
100 pub fn will_wake(&self, waker: &Waker) -> bool {
101 self.borrowed_waker().will_wake(waker)
102 }
103
104 #[inline]
108 pub fn into_waker(self) -> Waker {
109 let this = ManuallyDrop::new(self);
110 if this.is_native() {
111 unsafe { task::into_waker(this.data) }
112 } else {
113 unsafe { Waker::from_raw(this.raw_waker()) }
114 }
115 }
116
117 fn native(data: *const ()) -> Self {
118 Self {
119 data,
120 metadata: NATIVE,
121 _local: PhantomData,
122 }
123 }
124
125 fn fallback(waker: Waker) -> Self {
126 let waker = ManuallyDrop::new(waker);
127 Self {
128 data: waker.data(),
129 metadata: NonNull::from(waker.vtable()).cast(),
130 _local: PhantomData,
131 }
132 }
133
134 fn is_native(&self) -> bool {
135 self.metadata == NATIVE
136 }
137
138 fn raw_waker(&self) -> RawWaker {
139 if self.is_native() {
140 task::raw_waker(self.data)
141 } else {
142 RawWaker::new(self.data, unsafe {
144 self.metadata.cast::<RawWakerVTable>().as_ref()
145 })
146 }
147 }
148
149 fn borrowed_waker(&self) -> ManuallyDrop<Waker> {
150 ManuallyDrop::new(unsafe { Waker::from_raw(self.raw_waker()) })
152 }
153}
154
155impl From<Waker> for LocalWaker {
156 #[inline]
158 fn from(waker: Waker) -> Self {
159 if let Some(ptr) = task::local_waker_ptr(&waker) {
160 unsafe { task::clone_local_waker(ptr) };
161 drop(waker);
162 Self::native(ptr)
163 } else {
164 Self::fallback(waker)
165 }
166 }
167}
168
169impl Clone for LocalWaker {
170 #[inline]
171 fn clone(&self) -> Self {
172 if self.is_native() {
173 unsafe { task::clone_local_waker(self.data) };
174 Self::native(self.data)
175 } else {
176 Self::fallback((*self.borrowed_waker()).clone())
177 }
178 }
179
180 #[inline]
181 fn clone_from(&mut self, source: &Self) {
182 if self.data != source.data || self.metadata != source.metadata {
183 *self = source.clone();
184 }
185 }
186}
187
188impl Drop for LocalWaker {
189 #[inline]
190 fn drop(&mut self) {
191 if self.is_native() {
192 unsafe { task::drop_local_waker(self.data) };
193 } else {
194 drop(unsafe { Waker::from_raw(self.raw_waker()) });
195 }
196 }
197}
198
199impl fmt::Debug for LocalWaker {
200 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
201 f.debug_struct("LocalWaker")
202 .field("data", &self.data)
203 .field("native", &self.is_native())
204 .finish()
205 }
206}
207
208#[cfg(all(test, not(ntex_loom)))]
209mod tests {
210 use std::panic::{AssertUnwindSafe, catch_unwind};
211 use std::sync::atomic::{AtomicUsize, Ordering};
212 use std::task::{Poll, Wake};
213 use std::{future::poll_fn, ptr, sync::Arc};
214
215 use super::*;
216 use crate::Runner;
217
218 #[derive(Default)]
219 struct Counter(AtomicUsize);
220
221 impl Counter {
222 fn waker(counter: Arc<Self>) -> Waker {
224 unsafe fn clone(data: *const ()) -> RawWaker {
225 unsafe { Arc::increment_strong_count(data.cast::<Counter>()) };
226 RawWaker::new(data, &VTABLE)
227 }
228 unsafe fn wake(data: *const ()) {
229 let counter = unsafe { Arc::from_raw(data.cast::<Counter>()) };
230 counter.0.fetch_add(1, Ordering::Relaxed);
231 }
232 unsafe fn wake_by_ref(data: *const ()) {
233 unsafe { &*data.cast::<Counter>() }
234 .0
235 .fetch_add(1, Ordering::Relaxed);
236 }
237 unsafe fn drop(data: *const ()) {
238 std::mem::drop(unsafe { Arc::from_raw(data.cast::<Counter>()) });
239 }
240 static VTABLE: RawWakerVTable = RawWakerVTable::new(clone, wake, wake_by_ref, drop);
241 unsafe { Waker::from_raw(RawWaker::new(Arc::into_raw(counter).cast(), &VTABLE)) }
242 }
243 }
244
245 fn changing_waker(waker: Waker) -> Waker {
247 unsafe fn clone(data: *const ()) -> RawWaker {
248 let waker = ManuallyDrop::new(unsafe { &*data.cast::<Waker>() }.clone());
249 RawWaker::new(waker.data(), waker.vtable())
250 }
251 unsafe fn wake(data: *const ()) {
252 unsafe { Box::from_raw(data.cast_mut().cast::<Waker>()) }.wake();
253 }
254 unsafe fn wake_by_ref(data: *const ()) {
255 unsafe { &*data.cast::<Waker>() }.wake_by_ref();
256 }
257 unsafe fn drop(data: *const ()) {
258 std::mem::drop(unsafe { Box::from_raw(data.cast_mut().cast::<Waker>()) });
259 }
260 static VTABLE: RawWakerVTable = RawWakerVTable::new(clone, wake, wake_by_ref, drop);
261 unsafe {
262 Waker::from_raw(RawWaker::new(
263 Box::into_raw(Box::new(waker)).cast(),
264 &VTABLE,
265 ))
266 }
267 }
268
269 #[test]
270 fn fallback_clone_parts_and_owned_conversion() {
271 let counter = Arc::new(Counter::default());
272 {
273 let target = Counter::waker(counter.clone());
274 let original = changing_waker(target.clone());
275 let borrowed = LocalWaker::from_waker(&original);
276 assert!(!borrowed.is_native());
277 assert!(borrowed.will_wake(&target));
278 assert!(!borrowed.will_wake(&original));
279
280 let (data, vtable) = (original.data(), original.vtable());
281 let owned = LocalWaker::from(original);
282 let cloned = owned.clone();
283 assert!(cloned.will_wake(&target));
284 assert!(!owned.will_wake(&target));
285
286 let mut replaced = LocalWaker::from_waker(Waker::noop());
287 replaced.clone_from(&owned);
288 assert!(replaced.will_wake(&target));
289 borrowed.wake_by_ref();
290 cloned.wake();
291 replaced.wake();
292
293 let original = owned.into_waker();
294 assert_eq!(original.data(), data);
295 assert!(ptr::eq(original.vtable(), vtable));
296 original.wake();
297 }
298 assert_eq!(counter.0.load(Ordering::Relaxed), 4);
299 assert_eq!(Arc::strong_count(&counter), 1);
300 }
301
302 #[test]
303 fn fallback_null_data_and_clone_unwind() {
304 static PANIC: RawWakerVTable = RawWakerVTable::new(
305 |_| panic!("clone"),
306 |data| assert!(data.is_null()),
307 |data| assert!(data.is_null()),
308 |data| assert!(data.is_null()),
309 );
310 let waker = || unsafe { Waker::from_raw(RawWaker::new(ptr::null(), &PANIC)) };
311 let source = LocalWaker::from(waker());
312 let mut same = LocalWaker::from(waker());
313 same.clone_from(&source); same.wake_by_ref();
315 same.wake();
316 assert!(catch_unwind(|| LocalWaker::from_waker(&waker())).is_err());
317 assert!(catch_unwind(AssertUnwindSafe(|| source.clone())).is_err());
318
319 let counter = Arc::new(Counter::default());
320 let target = Counter::waker(counter.clone());
321 let mut destination = LocalWaker::from_waker(&target);
322 assert!(catch_unwind(AssertUnwindSafe(|| destination.clone_from(&source))).is_err());
323 assert!(destination.will_wake(&target));
324 destination.wake();
325 assert_eq!(counter.0.load(Ordering::Relaxed), 1);
326 }
327
328 #[test]
329 fn fallback_wake_and_drop_unwind() {
330 static VTABLE: RawWakerVTable = RawWakerVTable::new(
331 |data| {
332 unsafe { Arc::increment_strong_count(data.cast::<Counter>()) };
333 RawWaker::new(data, &VTABLE)
334 },
335 |data| {
336 let counter = unsafe { Arc::from_raw(data.cast::<Counter>()) };
337 counter.0.fetch_add(1, Ordering::Relaxed);
338 panic!("wake");
339 },
340 |data| {
341 unsafe { &*data.cast::<Counter>() }
342 .0
343 .fetch_add(1, Ordering::Relaxed);
344 panic!("wake_by_ref");
345 },
346 |data| {
347 let counter = unsafe { Arc::from_raw(data.cast::<Counter>()) };
348 counter.0.fetch_add(1, Ordering::Relaxed);
349 panic!("drop");
350 },
351 );
352 let counter = Arc::new(Counter::default());
353 let local = LocalWaker::from(unsafe {
354 Waker::from_raw(RawWaker::new(
355 Arc::into_raw(counter.clone()).cast(),
356 &VTABLE,
357 ))
358 });
359 assert!(catch_unwind(AssertUnwindSafe(|| local.wake_by_ref())).is_err());
360 assert_eq!(Arc::strong_count(&counter), 2);
361 assert!(catch_unwind(AssertUnwindSafe(|| local.clone().wake())).is_err());
362 assert_eq!(Arc::strong_count(&counter), 2);
363 assert!(catch_unwind(AssertUnwindSafe(|| drop(local))).is_err());
364 assert_eq!(Arc::strong_count(&counter), 1);
365 assert_eq!(counter.0.load(Ordering::Relaxed), 3);
366 }
367
368 #[test]
369 fn selected_runtime_and_wrapped_waker() {
370 struct Forward(Waker, Arc<Counter>);
371
372 impl Wake for Forward {
373 fn wake(self: Arc<Self>) {
374 self.1.0.fetch_add(1, Ordering::Relaxed);
375 self.0.wake_by_ref();
376 }
377 }
378
379 crate::testing::TestRunner
380 .block_on(Box::pin(async {
381 let mut polled = false;
382 let local = crate::spawn(poll_fn(move |cx| {
383 let local = LocalWaker::from_waker(cx.waker());
384 assert_eq!(
385 local.is_native(),
386 !cfg!(any(feature = "tokio", feature = "compio"))
387 );
388 assert!(local.will_wake(cx.waker()));
389 if polled {
390 return Poll::Ready(local);
391 }
392 polled = true;
393 let counter = Arc::new(Counter::default());
394 let wrapped =
395 Waker::from(Arc::new(Forward(cx.waker().clone(), counter.clone())));
396 let handle = LocalWaker::from_waker(&wrapped);
397 assert!(!handle.is_native());
398 handle.wake();
399 assert_eq!(counter.0.load(Ordering::Relaxed), 1);
400 local.wake();
401 Poll::Pending
402 }))
403 .await
404 .unwrap();
405 local.clone().wake();
406 local.into_waker().wake();
407 }))
408 .unwrap();
409 }
410}