blob: 635bfe8543152ec11f0975df191ecbd13df6d46d [file] [log] [blame]
Jason Macnakea22e812020-03-18 01:29:19 +00001use super::arc_wake::ArcWake;
2use core::mem;
3use core::task::{Waker, RawWaker, RawWakerVTable};
4use alloc::sync::Arc;
5
6pub(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.
19pub fn waker<W>(wake: Arc<W>) -> Waker
20where
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.
34unsafe 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`
42unsafe fn clone_arc_raw<T: ArcWake>(data: *const ()) -> RawWaker {
43 increase_refcount::<T>(data);
44 RawWaker::new(data, waker_vtable::<T>())
45}
46
47unsafe 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`
53unsafe 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
59unsafe fn drop_arc_raw<T: ArcWake>(data: *const ()) {
60 drop(Arc::<T>::from_raw(data as *const T))
61}