summaryrefslogtreecommitdiffstats
path: root/third_party/rust/futures-task/src/waker.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/futures-task/src/waker.rs')
-rw-r--r--third_party/rust/futures-task/src/waker.rs59
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>()))
+}