diff options
Diffstat (limited to 'third_party/rust/futures-task/src/waker.rs')
-rw-r--r-- | third_party/rust/futures-task/src/waker.rs | 59 |
1 files changed, 59 insertions, 0 deletions
diff --git a/third_party/rust/futures-task/src/waker.rs b/third_party/rust/futures-task/src/waker.rs new file mode 100644 index 0000000000..79112569c5 --- /dev/null +++ b/third_party/rust/futures-task/src/waker.rs @@ -0,0 +1,59 @@ +use super::arc_wake::ArcWake; +use alloc::sync::Arc; +use core::mem; +use core::task::{RawWaker, RawWakerVTable, Waker}; + +pub(super) fn waker_vtable<W: ArcWake>() -> &'static RawWakerVTable { + &RawWakerVTable::new( + clone_arc_raw::<W>, + wake_arc_raw::<W>, + wake_by_ref_arc_raw::<W>, + drop_arc_raw::<W>, + ) +} + +/// Creates a [`Waker`] from an `Arc<impl ArcWake>`. +/// +/// The returned [`Waker`] will call +/// [`ArcWake.wake()`](ArcWake::wake) if awoken. +pub fn waker<W>(wake: Arc<W>) -> Waker +where + W: ArcWake + 'static, +{ + let ptr = Arc::into_raw(wake).cast::<()>(); + + unsafe { Waker::from_raw(RawWaker::new(ptr, waker_vtable::<W>())) } +} + +// FIXME: panics on Arc::clone / refcount changes could wreak havoc on the +// code here. We should guard against this by aborting. + +#[allow(clippy::redundant_clone)] // The clone here isn't actually redundant. +unsafe fn increase_refcount<T: ArcWake>(data: *const ()) { + // Retain Arc, but don't touch refcount by wrapping in ManuallyDrop + let arc = mem::ManuallyDrop::new(Arc::<T>::from_raw(data.cast::<T>())); + // Now increase refcount, but don't drop new refcount either + let _arc_clone: mem::ManuallyDrop<_> = arc.clone(); +} + +// used by `waker_ref` +unsafe fn clone_arc_raw<T: ArcWake>(data: *const ()) -> RawWaker { + increase_refcount::<T>(data); + RawWaker::new(data, waker_vtable::<T>()) +} + +unsafe fn wake_arc_raw<T: ArcWake>(data: *const ()) { + let arc: Arc<T> = Arc::from_raw(data.cast::<T>()); + ArcWake::wake(arc); +} + +// used by `waker_ref` +unsafe fn wake_by_ref_arc_raw<T: ArcWake>(data: *const ()) { + // Retain Arc, but don't touch refcount by wrapping in ManuallyDrop + let arc = mem::ManuallyDrop::new(Arc::<T>::from_raw(data.cast::<T>())); + ArcWake::wake_by_ref(&arc); +} + +unsafe fn drop_arc_raw<T: ArcWake>(data: *const ()) { + drop(Arc::<T>::from_raw(data.cast::<T>())) +} |