1 use super::arc_wake::ArcWake;
2 use alloc::sync::Arc;
3 use core::mem;
4 use core::task::{RawWaker, RawWakerVTable, Waker};
5 
waker_vtable<W: ArcWake + 'static>() -> &'static RawWakerVTable6 pub(super) fn waker_vtable<W: ArcWake + 'static>() -> &'static RawWakerVTable {
7     &RawWakerVTable::new(
8         clone_arc_raw::<W>,
9         wake_arc_raw::<W>,
10         wake_by_ref_arc_raw::<W>,
11         drop_arc_raw::<W>,
12     )
13 }
14 
15 /// Creates a [`Waker`] from an `Arc<impl ArcWake>`.
16 ///
17 /// The returned [`Waker`] will call
18 /// [`ArcWake.wake()`](ArcWake::wake) if awoken.
waker<W>(wake: Arc<W>) -> Waker where W: ArcWake + 'static,19 pub fn waker<W>(wake: Arc<W>) -> Waker
20 where
21     W: ArcWake + 'static,
22 {
23     let ptr = Arc::into_raw(wake).cast::<()>();
24 
25     unsafe { Waker::from_raw(RawWaker::new(ptr, waker_vtable::<W>())) }
26 }
27 
28 // FIXME: panics on Arc::clone / refcount changes could wreak havoc on the
29 // code here. We should guard against this by aborting.
30 
31 #[allow(clippy::redundant_clone)] // The clone here isn't actually redundant.
increase_refcount<T: ArcWake + 'static>(data: *const ())32 unsafe fn increase_refcount<T: ArcWake + 'static>(data: *const ()) {
33     // Retain Arc, but don't touch refcount by wrapping in ManuallyDrop
34     let arc = mem::ManuallyDrop::new(unsafe { Arc::<T>::from_raw(data.cast::<T>()) });
35     // Now increase refcount, but don't drop new refcount either
36     let _arc_clone: mem::ManuallyDrop<_> = arc.clone();
37 }
38 
39 // used by `waker_ref`
40 #[inline(always)]
clone_arc_raw<T: ArcWake + 'static>(data: *const ()) -> RawWaker41 unsafe fn clone_arc_raw<T: ArcWake + 'static>(data: *const ()) -> RawWaker {
42     unsafe { increase_refcount::<T>(data) }
43     RawWaker::new(data, waker_vtable::<T>())
44 }
45 
wake_arc_raw<T: ArcWake + 'static>(data: *const ())46 unsafe fn wake_arc_raw<T: ArcWake + 'static>(data: *const ()) {
47     let arc: Arc<T> = unsafe { Arc::from_raw(data.cast::<T>()) };
48     ArcWake::wake(arc);
49 }
50 
51 // used by `waker_ref`
wake_by_ref_arc_raw<T: ArcWake + 'static>(data: *const ())52 unsafe fn wake_by_ref_arc_raw<T: ArcWake + 'static>(data: *const ()) {
53     // Retain Arc, but don't touch refcount by wrapping in ManuallyDrop
54     let arc = mem::ManuallyDrop::new(unsafe { Arc::<T>::from_raw(data.cast::<T>()) });
55     ArcWake::wake_by_ref(&arc);
56 }
57 
drop_arc_raw<T: ArcWake + 'static>(data: *const ())58 unsafe fn drop_arc_raw<T: ArcWake + 'static>(data: *const ()) {
59     drop(unsafe { Arc::<T>::from_raw(data.cast::<T>()) })
60 }
61