Skip to content

Commit

Permalink
Auto merge of #59733 - cramertj:wake-by-ref, r=withoutboats
Browse files Browse the repository at this point in the history
Final (one can only hope) futures_api adjustments

Based on #59119 -- this change is only the latter two commits.
cc #59725

r? @withoutboats
  • Loading branch information
bors committed Apr 12, 2019
2 parents 9a612b2 + 6786fa7 commit df25d79
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 24 deletions.
60 changes: 49 additions & 11 deletions src/libcore/task/wake.rs
Expand Up @@ -72,10 +72,18 @@ pub struct RawWakerVTable {
/// This function will be called when `wake` is called on the [`Waker`].
/// It must wake up the task associated with this [`RawWaker`].
///
/// The implemention of this function must not consume the provided data
/// pointer.
/// 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: 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.
///
/// The implementation of this function must make sure to release any
Expand All @@ -85,8 +93,8 @@ pub struct RawWakerVTable {
}

impl RawWakerVTable {
/// Creates a new `RawWakerVTable` from the provided `clone`, `wake`, and
/// `drop` functions.
/// Creates a new `RawWakerVTable` from the provided `clone`, `wake`,
/// `wake_by_ref`, and `drop` functions.
///
/// # `clone`
///
Expand All @@ -103,7 +111,16 @@ impl RawWakerVTable {
/// This function will be called when `wake` is called on the [`Waker`].
/// 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.
///
/// # `drop`
Expand All @@ -120,11 +137,13 @@ impl RawWakerVTable {
pub const fn new(
clone: unsafe fn(*const ()) -> RawWaker,
wake: unsafe fn(*const ()),
wake_by_ref: unsafe fn(*const ()),
drop: unsafe fn(*const ()),
) -> Self {
Self {
clone,
wake,
wake_by_ref,
drop,
}
}
Expand Down Expand Up @@ -187,14 +206,33 @@ unsafe impl Sync for Waker {}
impl Waker {
/// Wake up the task associated with this `Waker`.
#[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;

// SAFETY: This is safe because `Waker::new_unchecked` is the only way
// 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 { (self.waker.vtable.wake)(self.waker.data) }
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
// to the implementation which is defined by the executor.

// SAFETY: see `wake`
unsafe { (self.waker.vtable.wake_by_ref)(self.waker.data) }
}

/// Returns `true` if this `Waker` and another `Waker` have awoken the same task.
Expand All @@ -215,7 +253,7 @@ impl Waker {
/// in [`RawWaker`]'s and [`RawWakerVTable`]'s documentation is not upheld.
/// Therefore this method is unsafe.
#[inline]
pub unsafe fn new_unchecked(waker: RawWaker) -> Waker {
pub unsafe fn from_raw(waker: RawWaker) -> Waker {
Waker {
waker,
}
Expand All @@ -226,7 +264,7 @@ impl Clone for Waker {
#[inline]
fn clone(&self) -> Self {
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
// that the contract of [`RawWaker`] is upheld.
waker: unsafe { (self.waker.vtable.clone)(self.waker.data) },
Expand All @@ -237,7 +275,7 @@ impl Clone for Waker {
impl Drop for Waker {
#[inline]
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
// that the contract of `RawWaker` is upheld.
unsafe { (self.waker.vtable.drop)(self.waker.data) }
Expand Down
7 changes: 5 additions & 2 deletions src/test/run-pass/async-await.rs
Expand Up @@ -19,7 +19,10 @@ struct 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);
}
}
Expand All @@ -34,7 +37,7 @@ impl Future for WakeOnceThenComplete {
if self.0 {
Poll::Ready(())
} else {
cx.waker().wake();
cx.waker().wake_by_ref();
self.0 = true;
Poll::Pending
}
Expand Down
26 changes: 18 additions & 8 deletions src/test/run-pass/auxiliary/arc_wake.rs
Expand Up @@ -12,25 +12,30 @@ macro_rules! waker_vtable {
&RawWakerVTable::new(
clone_arc_raw::<$ty>,
wake_arc_raw::<$ty>,
wake_by_ref_arc_raw::<$ty>,
drop_arc_raw::<$ty>,
)
};
}

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
{
let ptr = Arc::into_raw(wake) as *const();
let ptr = Arc::into_raw(wake) as *const ();

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
let arc: Arc<T> = Arc::from_raw(data as *const T);
let arc_clone = arc.clone();
Expand All @@ -39,18 +44,23 @@ unsafe fn increase_refcount<T: ArcWake>(data: *const()) {
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);
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
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);
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(&arc);
ArcWake::wake_by_ref(&arc);
let _ = Arc::into_raw(arc);
}
9 changes: 6 additions & 3 deletions src/test/run-pass/futures-api.rs
Expand Up @@ -20,7 +20,10 @@ struct 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);
}
}
Expand All @@ -32,8 +35,8 @@ impl Future for MyFuture {
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
// Wake twice
let waker = cx.waker();
waker.wake();
waker.wake();
waker.wake_by_ref();
waker.wake_by_ref();
Poll::Ready(())
}
}
Expand Down

0 comments on commit df25d79

Please sign in to comment.