Rollup merge of #74304 - yoshuawuyts:stabilize-wake, r=KodrAus

Stabilize the Wake trait

This PR proposes stabilizing the `wake_trait` feature, tracking issue https://github.com/rust-lang/rust/issues/69912.

## Motivation

The surface area this trait introduces is small, and it has been on nightly for 4 months without any reported issues. Given the surface area of this trait is small and only serves to provide a safe interface around the already stable [`std::task::RawWakerVTable`](https://doc.rust-lang.org/std/task/struct.RawWaker.html) it seems unlikely this trait will require any further changes. So I'm proposing we stabilize this.

Personally I would love to have this available on stable, since it would enable cleaning up some runtime internals by removing the tedious pointer required to construct a [`RawWakerVTable`](https://doc.rust-lang.org/std/task/struct.RawWakerVTable.html). I believe the intent was always to introduce a `Wake` counterpart to `RawWaker` in order to safely construct `Waker` instances. And the `Wake` trait feels like it does that job as intended.

## Implementation notes

This PR itself fixes a link in the docs, and introduces an example of how to use the trait: a minimal `block_on` example that runs a future to completion on the current thread. It doesn't include fancier features such as support for nesting, but is intended to serve as a teaching device for both `task::Wake` and futures alike.
This commit is contained in:
Mara Bos 2021-02-04 21:10:31 +01:00 committed by GitHub
commit d20d097125
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 60 additions and 10 deletions

View file

@ -1,4 +1,4 @@
#![unstable(feature = "wake_trait", issue = "69912")] #![stable(feature = "wake_trait", since = "1.51.0")]
//! Types and Traits for working with asynchronous tasks. //! Types and Traits for working with asynchronous tasks.
use core::mem::ManuallyDrop; use core::mem::ManuallyDrop;
use core::task::{RawWaker, RawWakerVTable, Waker}; use core::task::{RawWaker, RawWakerVTable, Waker};
@ -16,18 +16,70 @@ use crate::sync::Arc;
/// to wake up a task is stored in an [`Arc`]. Some executors (especially /// to wake up a task is stored in an [`Arc`]. Some executors (especially
/// those for embedded systems) cannot use this API, which is why [`RawWaker`] /// those for embedded systems) cannot use this API, which is why [`RawWaker`]
/// exists as an alternative for those systems. /// exists as an alternative for those systems.
#[unstable(feature = "wake_trait", issue = "69912")] ///
/// [arc]: ../../std/sync/struct.Arc.html
///
/// # Examples
///
/// A basic `block_on` function that takes a future and runs it to completion on
/// the current thread.
///
/// **Note:** This example trades correctness for simplicity. In order to prevent
/// deadlocks, production-grade implementations will also need to handle
/// intermediate calls to `thread::unpark` as well as nested invocations.
///
/// ```rust
/// use std::future::Future;
/// use std::sync::Arc;
/// use std::task::{Context, Poll, Wake};
/// use std::thread::{self, Thread};
///
/// /// A waker that wakes up the current thread when called.
/// struct ThreadWaker(Thread);
///
/// impl Wake for ThreadWaker {
/// fn wake(self: Arc<Self>) {
/// self.0.unpark();
/// }
/// }
///
/// /// Run a future to completion on the current thread.
/// fn block_on<T>(fut: impl Future<Output = T>) -> T {
/// // Pin the future so it can be polled.
/// let mut fut = Box::pin(fut);
///
/// // Create a new context to be passed to the future.
/// let t = thread::current();
/// let waker = Arc::new(ThreadWaker(t)).into();
/// let mut cx = Context::from_waker(&waker);
///
/// // Run the future to completion.
/// loop {
/// match fut.as_mut().poll(&mut cx) {
/// Poll::Ready(res) => return res,
/// Poll::Pending => thread::park(),
/// }
/// }
/// }
///
/// block_on(async {
/// println!("Hi from inside a future!");
/// });
/// ```
#[stable(feature = "wake_trait", since = "1.51.0")]
pub trait Wake { pub trait Wake {
/// Wake this task. /// Wake this task.
#[unstable(feature = "wake_trait", issue = "69912")] #[stable(feature = "wake_trait", since = "1.51.0")]
fn wake(self: Arc<Self>); fn wake(self: Arc<Self>);
/// Wake this task without consuming the waker. /// Wake this task without consuming the waker.
/// ///
/// If an executor supports a cheaper way to wake without consuming the /// If an executor supports a cheaper way to wake without consuming the
/// waker, it should override this method. By default, it clones the /// waker, it should override this method. By default, it clones the
/// [`Arc`] and calls `wake` on the clone. /// [`Arc`] and calls [`wake`] on the clone.
#[unstable(feature = "wake_trait", issue = "69912")] ///
/// [`wake`]: Wake::wake
#[stable(feature = "wake_trait", since = "1.51.0")]
fn wake_by_ref(self: &Arc<Self>) { fn wake_by_ref(self: &Arc<Self>) {
self.clone().wake(); self.clone().wake();
} }
@ -35,7 +87,7 @@ pub trait Wake {
#[cfg_attr(bootstrap, allow(rustc::ineffective_unstable_trait_impl))] #[cfg_attr(bootstrap, allow(rustc::ineffective_unstable_trait_impl))]
#[cfg_attr(not(bootstrap), allow(ineffective_unstable_trait_impl))] #[cfg_attr(not(bootstrap), allow(ineffective_unstable_trait_impl))]
#[unstable(feature = "wake_trait", issue = "69912")] #[stable(feature = "wake_trait", since = "1.51.0")]
impl<W: Wake + Send + Sync + 'static> From<Arc<W>> for Waker { impl<W: Wake + Send + Sync + 'static> From<Arc<W>> for Waker {
fn from(waker: Arc<W>) -> Waker { fn from(waker: Arc<W>) -> Waker {
// SAFETY: This is safe because raw_waker safely constructs // SAFETY: This is safe because raw_waker safely constructs
@ -46,7 +98,7 @@ impl<W: Wake + Send + Sync + 'static> From<Arc<W>> for Waker {
#[cfg_attr(bootstrap, allow(rustc::ineffective_unstable_trait_impl))] #[cfg_attr(bootstrap, allow(rustc::ineffective_unstable_trait_impl))]
#[cfg_attr(not(bootstrap), allow(ineffective_unstable_trait_impl))] #[cfg_attr(not(bootstrap), allow(ineffective_unstable_trait_impl))]
#[unstable(feature = "wake_trait", issue = "69912")] #[stable(feature = "wake_trait", since = "1.51.0")]
impl<W: Wake + Send + Sync + 'static> From<Arc<W>> for RawWaker { impl<W: Wake + Send + Sync + 'static> From<Arc<W>> for RawWaker {
fn from(waker: Arc<W>) -> RawWaker { fn from(waker: Arc<W>) -> RawWaker {
raw_waker(waker) raw_waker(waker)

View file

@ -329,7 +329,6 @@
#![feature(unwind_attributes)] #![feature(unwind_attributes)]
#![feature(vec_into_raw_parts)] #![feature(vec_into_raw_parts)]
#![feature(vec_spare_capacity)] #![feature(vec_spare_capacity)]
#![feature(wake_trait)]
// NB: the above list is sorted to minimize merge conflicts. // NB: the above list is sorted to minimize merge conflicts.
#![default_lib_allocator] #![default_lib_allocator]
@ -508,7 +507,7 @@ pub mod task {
pub use core::task::*; pub use core::task::*;
#[doc(inline)] #[doc(inline)]
#[unstable(feature = "wake_trait", issue = "69912")] #[stable(feature = "wake_trait", since = "1.51.0")]
pub use alloc::task::*; pub use alloc::task::*;
} }

View file

@ -4,7 +4,6 @@
// edition:2018 // edition:2018
#![allow(dead_code)] #![allow(dead_code)]
#![feature(wake_trait)]
use std::future::Future; use std::future::Future;
use std::task::{Waker, Wake, Context}; use std::task::{Waker, Wake, Context};
use std::sync::Arc; use std::sync::Arc;