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 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 + 'static,19 pub fn waker<W>(wake: Arc<W>) -> Waker
20 where
21     W: ArcWake + 'static,
22 {
23     let ptr = Arc::into_raw(wake) as *const ();
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>(data: *const ())32 unsafe fn increase_refcount<T: ArcWake>(data: *const ()) {
33     // Retain Arc, but don't touch refcount by wrapping in ManuallyDrop
34     let arc = mem::ManuallyDrop::new(Arc::<T>::from_raw(data as *const 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`
clone_arc_raw<T: ArcWake>(data: *const ()) -> RawWaker40 unsafe fn clone_arc_raw<T: ArcWake>(data: *const ()) -> RawWaker {
41     increase_refcount::<T>(data);
42     RawWaker::new(data, waker_vtable::<T>())
43 }
44 
wake_arc_raw<T: ArcWake>(data: *const ())45 unsafe fn wake_arc_raw<T: ArcWake>(data: *const ()) {
46     let arc: Arc<T> = Arc::from_raw(data as *const T);
47     ArcWake::wake(arc);
48 }
49 
50 // used by `waker_ref`
wake_by_ref_arc_raw<T: ArcWake>(data: *const ())51 unsafe fn wake_by_ref_arc_raw<T: ArcWake>(data: *const ()) {
52     // Retain Arc, but don't touch refcount by wrapping in ManuallyDrop
53     let arc = mem::ManuallyDrop::new(Arc::<T>::from_raw(data as *const T));
54     ArcWake::wake_by_ref(&arc);
55 }
56 
drop_arc_raw<T: ArcWake>(data: *const ())57 unsafe fn drop_arc_raw<T: ArcWake>(data: *const ()) {
58     drop(Arc::<T>::from_raw(data as *const T))
59 }
60