Skip to content

Commit 25465d5

Browse files
committed
Cleanup futures_util::task RawWaker vtables
1 parent f7e5f64 commit 25465d5

File tree

3 files changed

+38
-71
lines changed

3 files changed

+38
-71
lines changed

futures-util/src/task/arc_wake.rs

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,7 @@
1+
use std::mem;
12
use std::sync::Arc;
23
use std::task::{Waker, RawWaker, RawWakerVTable};
34

4-
macro_rules! waker_vtable {
5-
($ty:ident) => {
6-
&RawWakerVTable {
7-
clone: clone_arc_raw::<$ty>,
8-
drop: drop_arc_raw::<$ty>,
9-
wake: wake_arc_raw::<$ty>,
10-
}
11-
};
12-
}
13-
145
/// A way of waking up a specific task.
156
///
167
/// By implementing this trait, types that are expected to be wrapped in an `Arc`
@@ -42,29 +33,33 @@ pub trait ArcWake {
4233
}
4334
}
4435

36+
// FIXME: panics on Arc::clone / refcount changes could wreak havoc on the
37+
// code here. We should guard against this by aborting.
38+
4539
unsafe fn increase_refcount<T: ArcWake>(data: *const()) {
4640
// Retain Arc by creating a copy
4741
let arc: Arc<T> = Arc::from_raw(data as *const T);
4842
let arc_clone = arc.clone();
4943
// Forget the Arcs again, so that the refcount isn't decrased
50-
let _ = Arc::into_raw(arc);
51-
let _ = Arc::into_raw(arc_clone);
44+
mem::forget(arc);
45+
mem::forget(arc_clone);
5246
}
5347

54-
unsafe fn clone_arc_raw<T: ArcWake>(data: *const()) -> RawWaker {
48+
// used by `waker_ref`
49+
pub(super) unsafe fn clone_arc_raw<T: ArcWake>(data: *const()) -> RawWaker {
5550
increase_refcount::<T>(data);
5651
RawWaker::new(data, waker_vtable!(T))
5752
}
5853

5954
unsafe fn drop_arc_raw<T: ArcWake>(data: *const()) {
60-
// Drop Arc
61-
let _: Arc<T> = Arc::from_raw(data as *const T);
55+
drop(Arc::<T>::from_raw(data as *const T))
6256
}
6357

64-
unsafe fn wake_arc_raw<T: ArcWake>(data: *const()) {
58+
// used by `waker_ref`
59+
pub(super) unsafe fn wake_arc_raw<T: ArcWake>(data: *const()) {
6560
let arc: Arc<T> = Arc::from_raw(data as *const T);
66-
ArcWake::wake(&arc); // TODO: If this panics, the refcount is too big
67-
let _ = Arc::into_raw(arc);
61+
ArcWake::wake(&arc);
62+
mem::forget(arc);
6863
}
6964

7065
#[cfg(test)]
@@ -115,4 +110,4 @@ mod tests {
115110
drop(w1);
116111
assert_eq!(1, Arc::strong_count(&some_w));
117112
}
118-
}
113+
}

futures-util/src/task/mod.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
//! Task notification
22
3+
/// A macro for creating a `RawWaker` vtable for a type that implements
4+
/// the `ArcWake` trait.
5+
macro_rules! waker_vtable {
6+
($ty:ident) => {
7+
&RawWakerVTable {
8+
clone: clone_arc_raw::<$ty>,
9+
drop: drop_arc_raw::<$ty>,
10+
wake: wake_arc_raw::<$ty>,
11+
}
12+
};
13+
}
14+
315
#[cfg(feature = "std")]
416
mod arc_wake;
517
#[cfg(feature = "std")]

futures-util/src/task/waker_ref.rs

Lines changed: 12 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
#![allow(clippy::cast_ptr_alignment)] // clippy is too strict here
22

3+
use super::arc_wake::{ArcWake, clone_arc_raw, wake_arc_raw};
34
use std::marker::PhantomData;
45
use std::ops::Deref;
56
use std::sync::Arc;
67
use std::task::{Waker, RawWaker, RawWakerVTable};
7-
use super::ArcWake;
88

99
/// A [`Waker`](::std::task::Waker) that is only valid for a given lifetime.
1010
///
@@ -38,28 +38,8 @@ impl<'a> Deref for WakerRef<'a> {
3838
}
3939
}
4040

41-
// Another reference vtable which doesn't do decrement the refcount on drop.
42-
// However on clone it will create a vtable which equals a Waker, and on wake
43-
// it will call the nonlocal wake function.
44-
macro_rules! ref_vtable {
45-
($ty:ident) => {
46-
&RawWakerVTable {
47-
clone: clone_arc_raw::<$ty>,
48-
drop: noop,
49-
wake: wake_arc_raw::<$ty>,
50-
}
51-
};
52-
}
53-
54-
macro_rules! owned_vtable {
55-
($ty:ident) => {
56-
&RawWakerVTable {
57-
clone: clone_arc_raw::<$ty>,
58-
drop: drop_arc_raw::<$ty>,
59-
wake: wake_arc_raw::<$ty>,
60-
}
61-
};
62-
}
41+
#[inline]
42+
unsafe fn noop(_data: *const ()) {}
6343

6444
/// Creates a reference to a [`Waker`](::std::task::Waker)
6545
/// from a local [`wake`](::std::task::Wake).
@@ -75,36 +55,16 @@ where
7555
// This is potentially not stable
7656
let ptr = &*wake as &W as *const W as *const();
7757

58+
// Similar to `waker_vtable`, but with a no-op `drop` function.
59+
// Clones of the resulting `RawWaker` will still be dropped normally.
60+
let vtable = &RawWakerVTable {
61+
clone: clone_arc_raw::<W>,
62+
drop: noop,
63+
wake: wake_arc_raw::<W>,
64+
};
65+
7866
let waker = unsafe {
79-
Waker::new_unchecked(RawWaker::new(ptr, ref_vtable!(W)))
67+
Waker::new_unchecked(RawWaker::new(ptr, vtable))
8068
};
8169
WakerRef::new(waker)
8270
}
83-
84-
unsafe fn noop(_data: *const()) {
85-
}
86-
87-
unsafe fn increase_refcount<T: ArcWake>(data: *const()) {
88-
// Retain Arc by creating a copy
89-
let arc: Arc<T> = Arc::from_raw(data as *const T);
90-
let arc_clone = arc.clone();
91-
// Forget the Arcs again, so that the refcount isn't decrased
92-
let _ = Arc::into_raw(arc);
93-
let _ = Arc::into_raw(arc_clone);
94-
}
95-
96-
unsafe fn clone_arc_raw<T: ArcWake>(data: *const()) -> RawWaker {
97-
increase_refcount::<T>(data);
98-
RawWaker::new(data, owned_vtable!(T))
99-
}
100-
101-
unsafe fn drop_arc_raw<T: ArcWake>(data: *const()) {
102-
// Drop Arc
103-
let _: Arc<T> = Arc::from_raw(data as *const T);
104-
}
105-
106-
unsafe fn wake_arc_raw<T: ArcWake>(data: *const()) {
107-
let arc: Arc<T> = Arc::from_raw(data as *const T);
108-
ArcWake::wake(&arc); // TODO: If this panics, the refcount is too big
109-
let _ = Arc::into_raw(arc);
110-
}

0 commit comments

Comments
 (0)