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