Skip to content

LocalWaker and Waker cleanups #54732

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 10, 2018
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 33 additions & 32 deletions src/libcore/task/wake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
reason = "futures in libcore are unstable",
issue = "50547")]

use {fmt, mem};
use fmt;
use marker::Unpin;
use ptr::NonNull;

Expand Down Expand Up @@ -63,6 +63,20 @@ impl Waker {
pub fn will_wake(&self, other: &Waker) -> bool {
self.inner == other.inner
}

/// Returns whether or not this `Waker` and `other` `LocalWaker` awaken
/// the same task.
///
/// This function works on a best-effort basis, and may return false even
/// when the `Waker`s would awaken the same task. However, if this function
/// returns true, it is guaranteed that the `Waker`s will awaken the same
/// task.
///
/// This function is primarily used for optimization purposes.
#[inline]
pub fn will_wake_local(&self, other: &LocalWaker) -> bool {
self.will_wake(&other.0)
}
}

impl Clone for Waker {
Expand Down Expand Up @@ -97,9 +111,8 @@ impl Drop for Waker {
/// Task executors can use this type to implement more optimized singlethreaded wakeup
/// behavior.
#[repr(transparent)]
pub struct LocalWaker {
inner: NonNull<dyn UnsafeWake>,
}
#[derive(Clone)]
pub struct LocalWaker(Waker);

impl Unpin for LocalWaker {}
impl !Send for LocalWaker {}
Expand All @@ -120,7 +133,16 @@ impl LocalWaker {
/// on the current thread.
#[inline]
pub unsafe fn new(inner: NonNull<dyn UnsafeWake>) -> Self {
LocalWaker { inner }
LocalWaker(Waker::new(inner))
}

/// Borrows this `LocalWaker` as a `Waker`.
///
/// `Waker` is nearly identical to `LocalWaker`, but is threadsafe
/// (implements `Send` and `Sync`).
#[inline]
pub fn as_waker(&self) -> &Waker {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this actually safe? With scoped threads it seems like you could use this to pass a LocalWaker to another thread as a &Waker?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, you can! And that's totally safe, because you can only call .wake() on the inner UnsafeWake in a Wake-- you can't call .wake_local().

&self.0
}

/// Converts this `LocalWaker` into a `Waker`.
Expand All @@ -129,13 +151,13 @@ impl LocalWaker {
/// (implements `Send` and `Sync`).
#[inline]
pub fn into_waker(self) -> Waker {
self.into()
self.0
}

/// Wake up the task associated with this `LocalWaker`.
#[inline]
pub fn wake(&self) {
unsafe { self.inner.as_ref().wake_local() }
unsafe { self.0.inner.as_ref().wake_local() }
}

/// Returns whether or not this `LocalWaker` and `other` `LocalWaker` awaken the same task.
Expand All @@ -148,7 +170,7 @@ impl LocalWaker {
/// This function is primarily used for optimization purposes.
#[inline]
pub fn will_wake(&self, other: &LocalWaker) -> bool {
self.inner == other.inner
self.0.will_wake(&other.0)
}

/// Returns whether or not this `LocalWaker` and `other` `Waker` awaken the same task.
Expand All @@ -161,45 +183,24 @@ impl LocalWaker {
/// This function is primarily used for optimization purposes.
#[inline]
pub fn will_wake_nonlocal(&self, other: &Waker) -> bool {
self.inner == other.inner
self.0.will_wake(other)
}
}

impl From<LocalWaker> for Waker {
#[inline]
fn from(local_waker: LocalWaker) -> Self {
let inner = local_waker.inner;
mem::forget(local_waker);
Waker { inner }
}
}

impl Clone for LocalWaker {
#[inline]
fn clone(&self) -> Self {
let waker = unsafe { self.inner.as_ref().clone_raw() };
let inner = waker.inner;
mem::forget(waker);
LocalWaker { inner }
local_waker.0
}
}

impl fmt::Debug for LocalWaker {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Waker")
f.debug_struct("LocalWaker")
.finish()
}
}

impl Drop for LocalWaker {
#[inline]
fn drop(&mut self) {
unsafe {
self.inner.as_ref().drop_raw()
}
}
}

/// An unsafe trait for implementing custom memory management for a `Waker` or `LocalWaker`.
///
/// A `Waker` conceptually is a cloneable trait object for `Wake`, and is
Expand Down