Jason Macnak | ea22e81 | 2020-03-18 01:29:19 +0000 | [diff] [blame^] | 1 | use super::arc_wake::ArcWake; |
| 2 | use core::mem; |
| 3 | use core::task::{Waker, RawWaker, RawWakerVTable}; |
| 4 | use alloc::sync::Arc; |
| 5 | |
| 6 | 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. |
| 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. |
| 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` |
| 42 | unsafe fn clone_arc_raw<T: ArcWake>(data: *const ()) -> RawWaker { |
| 43 | increase_refcount::<T>(data); |
| 44 | RawWaker::new(data, waker_vtable::<T>()) |
| 45 | } |
| 46 | |
| 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` |
| 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 | |
| 59 | unsafe fn drop_arc_raw<T: ArcWake>(data: *const ()) { |
| 60 | drop(Arc::<T>::from_raw(data as *const T)) |
| 61 | } |