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 + '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 {
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