Auto merge of #59733 - cramertj:wake-by-ref, r=withoutboats
Final (one can only hope) futures_api adjustments Based on https://github.com/rust-lang/rust/pull/59119 -- this change is only the latter two commits. cc https://github.com/rust-lang/rust/issues/59725 r? @withoutboats
This commit is contained in:
commit
df25d79a33
@ -72,10 +72,18 @@ pub struct RawWakerVTable {
|
|||||||
/// This function will be called when `wake` is called on the [`Waker`].
|
/// This function will be called when `wake` is called on the [`Waker`].
|
||||||
/// It must wake up the task associated with this [`RawWaker`].
|
/// It must wake up the task associated with this [`RawWaker`].
|
||||||
///
|
///
|
||||||
/// The implemention of this function must not consume the provided data
|
/// The implementation of this function must make sure to release any
|
||||||
/// pointer.
|
/// resources that are associated with this instance of a [`RawWaker`] and
|
||||||
|
/// associated task.
|
||||||
wake: unsafe fn(*const ()),
|
wake: unsafe fn(*const ()),
|
||||||
|
|
||||||
|
/// This function will be called when `wake_by_ref` is called on the [`Waker`].
|
||||||
|
/// It must wake up the task associated with this [`RawWaker`].
|
||||||
|
///
|
||||||
|
/// This function is similar to `wake`, but must not consume the provided data
|
||||||
|
/// pointer.
|
||||||
|
wake_by_ref: unsafe fn(*const ()),
|
||||||
|
|
||||||
/// This function gets called when a [`RawWaker`] gets dropped.
|
/// This function gets called when a [`RawWaker`] gets dropped.
|
||||||
///
|
///
|
||||||
/// The implementation of this function must make sure to release any
|
/// The implementation of this function must make sure to release any
|
||||||
@ -85,8 +93,8 @@ pub struct RawWakerVTable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl RawWakerVTable {
|
impl RawWakerVTable {
|
||||||
/// Creates a new `RawWakerVTable` from the provided `clone`, `wake`, and
|
/// Creates a new `RawWakerVTable` from the provided `clone`, `wake`,
|
||||||
/// `drop` functions.
|
/// `wake_by_ref`, and `drop` functions.
|
||||||
///
|
///
|
||||||
/// # `clone`
|
/// # `clone`
|
||||||
///
|
///
|
||||||
@ -103,7 +111,16 @@ impl RawWakerVTable {
|
|||||||
/// This function will be called when `wake` is called on the [`Waker`].
|
/// This function will be called when `wake` is called on the [`Waker`].
|
||||||
/// It must wake up the task associated with this [`RawWaker`].
|
/// It must wake up the task associated with this [`RawWaker`].
|
||||||
///
|
///
|
||||||
/// The implemention of this function must not consume the provided data
|
/// The implementation of this function must make sure to release any
|
||||||
|
/// resources that are associated with this instance of a [`RawWaker`] and
|
||||||
|
/// associated task.
|
||||||
|
///
|
||||||
|
/// # `wake_by_ref`
|
||||||
|
///
|
||||||
|
/// This function will be called when `wake_by_ref` is called on the [`Waker`].
|
||||||
|
/// It must wake up the task associated with this [`RawWaker`].
|
||||||
|
///
|
||||||
|
/// This function is similar to `wake`, but must not consume the provided data
|
||||||
/// pointer.
|
/// pointer.
|
||||||
///
|
///
|
||||||
/// # `drop`
|
/// # `drop`
|
||||||
@ -120,11 +137,13 @@ impl RawWakerVTable {
|
|||||||
pub const fn new(
|
pub const fn new(
|
||||||
clone: unsafe fn(*const ()) -> RawWaker,
|
clone: unsafe fn(*const ()) -> RawWaker,
|
||||||
wake: unsafe fn(*const ()),
|
wake: unsafe fn(*const ()),
|
||||||
|
wake_by_ref: unsafe fn(*const ()),
|
||||||
drop: unsafe fn(*const ()),
|
drop: unsafe fn(*const ()),
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
clone,
|
clone,
|
||||||
wake,
|
wake,
|
||||||
|
wake_by_ref,
|
||||||
drop,
|
drop,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -187,14 +206,33 @@ unsafe impl Sync for Waker {}
|
|||||||
impl Waker {
|
impl Waker {
|
||||||
/// Wake up the task associated with this `Waker`.
|
/// Wake up the task associated with this `Waker`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn wake(&self) {
|
pub fn wake(self) {
|
||||||
|
// The actual wakeup call is delegated through a virtual function call
|
||||||
|
// to the implementation which is defined by the executor.
|
||||||
|
let wake = self.waker.vtable.wake;
|
||||||
|
let data = self.waker.data;
|
||||||
|
|
||||||
|
// Don't call `drop` -- the waker will be consumed by `wake`.
|
||||||
|
crate::mem::forget(self);
|
||||||
|
|
||||||
|
// SAFETY: This is safe because `Waker::from_raw` is the only way
|
||||||
|
// to initialize `wake` and `data` requiring the user to acknowledge
|
||||||
|
// that the contract of `RawWaker` is upheld.
|
||||||
|
unsafe { (wake)(data) };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Wake up the task associated with this `Waker` without consuming the `Waker`.
|
||||||
|
///
|
||||||
|
/// This is similar to `wake`, but may be slightly less efficient in the case
|
||||||
|
/// where an owned `Waker` is available. This method should be preferred to
|
||||||
|
/// calling `waker.clone().wake()`.
|
||||||
|
#[inline]
|
||||||
|
pub fn wake_by_ref(&self) {
|
||||||
// The actual wakeup call is delegated through a virtual function call
|
// The actual wakeup call is delegated through a virtual function call
|
||||||
// to the implementation which is defined by the executor.
|
// to the implementation which is defined by the executor.
|
||||||
|
|
||||||
// SAFETY: This is safe because `Waker::new_unchecked` is the only way
|
// SAFETY: see `wake`
|
||||||
// to initialize `wake` and `data` requiring the user to acknowledge
|
unsafe { (self.waker.vtable.wake_by_ref)(self.waker.data) }
|
||||||
// that the contract of `RawWaker` is upheld.
|
|
||||||
unsafe { (self.waker.vtable.wake)(self.waker.data) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` if this `Waker` and another `Waker` have awoken the same task.
|
/// Returns `true` if this `Waker` and another `Waker` have awoken the same task.
|
||||||
@ -215,7 +253,7 @@ impl Waker {
|
|||||||
/// in [`RawWaker`]'s and [`RawWakerVTable`]'s documentation is not upheld.
|
/// in [`RawWaker`]'s and [`RawWakerVTable`]'s documentation is not upheld.
|
||||||
/// Therefore this method is unsafe.
|
/// Therefore this method is unsafe.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn new_unchecked(waker: RawWaker) -> Waker {
|
pub unsafe fn from_raw(waker: RawWaker) -> Waker {
|
||||||
Waker {
|
Waker {
|
||||||
waker,
|
waker,
|
||||||
}
|
}
|
||||||
@ -226,7 +264,7 @@ impl Clone for Waker {
|
|||||||
#[inline]
|
#[inline]
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
Waker {
|
Waker {
|
||||||
// SAFETY: This is safe because `Waker::new_unchecked` is the only way
|
// SAFETY: This is safe because `Waker::from_raw` is the only way
|
||||||
// to initialize `clone` and `data` requiring the user to acknowledge
|
// to initialize `clone` and `data` requiring the user to acknowledge
|
||||||
// that the contract of [`RawWaker`] is upheld.
|
// that the contract of [`RawWaker`] is upheld.
|
||||||
waker: unsafe { (self.waker.vtable.clone)(self.waker.data) },
|
waker: unsafe { (self.waker.vtable.clone)(self.waker.data) },
|
||||||
@ -237,7 +275,7 @@ impl Clone for Waker {
|
|||||||
impl Drop for Waker {
|
impl Drop for Waker {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
// SAFETY: This is safe because `Waker::new_unchecked` is the only way
|
// SAFETY: This is safe because `Waker::from_raw` is the only way
|
||||||
// to initialize `drop` and `data` requiring the user to acknowledge
|
// to initialize `drop` and `data` requiring the user to acknowledge
|
||||||
// that the contract of `RawWaker` is upheld.
|
// that the contract of `RawWaker` is upheld.
|
||||||
unsafe { (self.waker.vtable.drop)(self.waker.data) }
|
unsafe { (self.waker.vtable.drop)(self.waker.data) }
|
||||||
|
@ -19,7 +19,10 @@ struct Counter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ArcWake for Counter {
|
impl ArcWake for Counter {
|
||||||
fn wake(arc_self: &Arc<Self>) {
|
fn wake(self: Arc<Self>) {
|
||||||
|
Self::wake_by_ref(&self)
|
||||||
|
}
|
||||||
|
fn wake_by_ref(arc_self: &Arc<Self>) {
|
||||||
arc_self.wakes.fetch_add(1, atomic::Ordering::SeqCst);
|
arc_self.wakes.fetch_add(1, atomic::Ordering::SeqCst);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -34,7 +37,7 @@ impl Future for WakeOnceThenComplete {
|
|||||||
if self.0 {
|
if self.0 {
|
||||||
Poll::Ready(())
|
Poll::Ready(())
|
||||||
} else {
|
} else {
|
||||||
cx.waker().wake();
|
cx.waker().wake_by_ref();
|
||||||
self.0 = true;
|
self.0 = true;
|
||||||
Poll::Pending
|
Poll::Pending
|
||||||
}
|
}
|
||||||
|
@ -12,25 +12,30 @@ macro_rules! waker_vtable {
|
|||||||
&RawWakerVTable::new(
|
&RawWakerVTable::new(
|
||||||
clone_arc_raw::<$ty>,
|
clone_arc_raw::<$ty>,
|
||||||
wake_arc_raw::<$ty>,
|
wake_arc_raw::<$ty>,
|
||||||
|
wake_by_ref_arc_raw::<$ty>,
|
||||||
drop_arc_raw::<$ty>,
|
drop_arc_raw::<$ty>,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ArcWake {
|
pub trait ArcWake {
|
||||||
fn wake(arc_self: &Arc<Self>);
|
fn wake(self: Arc<Self>);
|
||||||
|
|
||||||
|
fn wake_by_ref(arc_self: &Arc<Self>) {
|
||||||
|
arc_self.clone().wake()
|
||||||
|
}
|
||||||
|
|
||||||
fn into_waker(wake: Arc<Self>) -> Waker where Self: Sized
|
fn into_waker(wake: Arc<Self>) -> Waker where Self: Sized
|
||||||
{
|
{
|
||||||
let ptr = Arc::into_raw(wake) as *const();
|
let ptr = Arc::into_raw(wake) as *const ();
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
Waker::new_unchecked(RawWaker::new(ptr, waker_vtable!(Self)))
|
Waker::from_raw(RawWaker::new(ptr, waker_vtable!(Self)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn increase_refcount<T: ArcWake>(data: *const()) {
|
unsafe fn increase_refcount<T: ArcWake>(data: *const ()) {
|
||||||
// Retain Arc by creating a copy
|
// Retain Arc by creating a copy
|
||||||
let arc: Arc<T> = Arc::from_raw(data as *const T);
|
let arc: Arc<T> = Arc::from_raw(data as *const T);
|
||||||
let arc_clone = arc.clone();
|
let arc_clone = arc.clone();
|
||||||
@ -39,18 +44,23 @@ unsafe fn increase_refcount<T: ArcWake>(data: *const()) {
|
|||||||
let _ = Arc::into_raw(arc_clone);
|
let _ = Arc::into_raw(arc_clone);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn clone_arc_raw<T: ArcWake>(data: *const()) -> RawWaker {
|
unsafe fn clone_arc_raw<T: ArcWake>(data: *const ()) -> RawWaker {
|
||||||
increase_refcount::<T>(data);
|
increase_refcount::<T>(data);
|
||||||
RawWaker::new(data, waker_vtable!(T))
|
RawWaker::new(data, waker_vtable!(T))
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn drop_arc_raw<T: ArcWake>(data: *const()) {
|
unsafe fn drop_arc_raw<T: ArcWake>(data: *const ()) {
|
||||||
// Drop Arc
|
// Drop Arc
|
||||||
let _: Arc<T> = Arc::from_raw(data as *const T);
|
let _: Arc<T> = Arc::from_raw(data as *const T);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn wake_arc_raw<T: ArcWake>(data: *const()) {
|
unsafe fn wake_arc_raw<T: ArcWake>(data: *const ()) {
|
||||||
let arc: Arc<T> = Arc::from_raw(data as *const T);
|
let arc: Arc<T> = Arc::from_raw(data as *const T);
|
||||||
ArcWake::wake(&arc);
|
ArcWake::wake(arc);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn wake_by_ref_arc_raw<T: ArcWake>(data: *const ()) {
|
||||||
|
let arc: Arc<T> = Arc::from_raw(data as *const T);
|
||||||
|
ArcWake::wake_by_ref(&arc);
|
||||||
let _ = Arc::into_raw(arc);
|
let _ = Arc::into_raw(arc);
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,10 @@ struct Counter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ArcWake for Counter {
|
impl ArcWake for Counter {
|
||||||
fn wake(arc_self: &Arc<Self>) {
|
fn wake(self: Arc<Self>) {
|
||||||
|
Self::wake_by_ref(&self)
|
||||||
|
}
|
||||||
|
fn wake_by_ref(arc_self: &Arc<Self>) {
|
||||||
arc_self.wakes.fetch_add(1, atomic::Ordering::SeqCst);
|
arc_self.wakes.fetch_add(1, atomic::Ordering::SeqCst);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -32,8 +35,8 @@ impl Future for MyFuture {
|
|||||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
// Wake twice
|
// Wake twice
|
||||||
let waker = cx.waker();
|
let waker = cx.waker();
|
||||||
waker.wake();
|
waker.wake_by_ref();
|
||||||
waker.wake();
|
waker.wake_by_ref();
|
||||||
Poll::Ready(())
|
Poll::Ready(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user