From 5e55bad6750e8552d43456ca0d321055f798dac7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Vallotton?= Date: Sat, 13 Jan 2024 14:57:13 -0300 Subject: [PATCH] refactor: make waker mandatory. This also removes * impl From<&Context> for ContextBuilder * Context::try_waker() The from implementation is removed because now that wakers are always supported, there are less incentives to override the current context. Before, the incentive was to add Waker support to a reactor that didn't have any. --- library/alloc/src/task.rs | 16 ++++-- library/core/src/task/wake.rs | 101 +++++++--------------------------- 2 files changed, 30 insertions(+), 87 deletions(-) diff --git a/library/alloc/src/task.rs b/library/alloc/src/task.rs index 7dad2f3f82270..357f7e0650ae7 100644 --- a/library/alloc/src/task.rs +++ b/library/alloc/src/task.rs @@ -173,14 +173,16 @@ fn raw_waker(waker: Arc) -> RawWaker { /// /// This is a simplified example of a `spawn` and a `block_on` function. The `spawn` function /// is used to push new tasks onto the run queue, while the block on function will remove them -/// and poll them. When a task is woken, it will put itself back on the run queue to be polled by the executor. +/// and poll them. When a task is woken, it will put itself back on the run queue to be polled +/// by the executor. /// -/// **Note:** A real world example would interleave poll calls with calls to an io reactor to wait for events instead -/// of spinning on a loop. +/// **Note:** This example trades correctness for simplicity. A real world example would interleave +/// poll calls with calls to an io reactor to wait for events instead of spinning on a loop. /// /// ```rust /// #![feature(local_waker)] -/// use std::task::{LocalWake, ContextBuilder, LocalWaker}; +/// #![feature(noop_waker)] +/// use std::task::{LocalWake, ContextBuilder, LocalWaker, Waker}; /// use std::future::Future; /// use std::pin::Pin; /// use std::rc::Rc; @@ -225,10 +227,12 @@ fn raw_waker(waker: Arc) -> RawWaker { /// // we exit, since there are no more tasks remaining on the queue /// return; /// }; +/// let waker = Waker::noop(); /// // cast the Rc into a `LocalWaker` -/// let waker: LocalWaker = task.clone().into(); +/// let local_waker: LocalWaker = task.clone().into(); /// // Build the context using `ContextBuilder` -/// let mut cx = ContextBuilder::from_local_waker(&waker) +/// let mut cx = ContextBuilder::from_waker(&waker) +/// .local_waker(&local_waker) /// .build(); /// /// // Poll the task diff --git a/library/core/src/task/wake.rs b/library/core/src/task/wake.rs index 830ebda4b3fef..64ee5e90524c6 100644 --- a/library/core/src/task/wake.rs +++ b/library/core/src/task/wake.rs @@ -217,7 +217,7 @@ impl RawWakerVTable { #[stable(feature = "futures_api", since = "1.36.0")] #[lang = "Context"] pub struct Context<'a> { - waker: Option<&'a Waker>, + waker: &'a Waker, local_waker: &'a LocalWaker, // Ensure we future-proof against variance changes by forcing // the lifetime to be invariant (argument-position lifetimes @@ -245,9 +245,7 @@ impl<'a> Context<'a> { #[stable(feature = "futures_api", since = "1.36.0")] #[rustc_const_unstable(feature = "const_waker", issue = "102012")] pub const fn waker(&self) -> &'a Waker { - &self - .waker - .expect("no waker was set on this context, consider calling `local_waker` instead.") + &self.waker } /// Returns a reference to the [`LocalWaker`] for the current task. #[inline] @@ -256,14 +254,6 @@ impl<'a> Context<'a> { pub const fn local_waker(&self) -> &'a LocalWaker { &self.local_waker } - /// Returns a `Some(&Waker)` if a waker was defined on the `Context`, - /// otherwise it returns `None`. - #[inline] - #[rustc_const_unstable(feature = "const_waker", issue = "102012")] - #[unstable(feature = "local_waker", issue = "118959")] - pub const fn try_waker(&self) -> Option<&'a Waker> { - self.waker - } } #[stable(feature = "futures_api", since = "1.36.0")] @@ -286,8 +276,8 @@ impl fmt::Debug for Context<'_> { /// let local_waker = LocalWaker::noop(); /// let waker = Waker::noop(); /// -/// let mut cx = ContextBuilder::from_local_waker(&local_waker) -/// .waker(&waker) +/// let mut cx = ContextBuilder::from_waker(&waker) +/// .local_waker(&local_waker) /// .build(); /// /// let mut future = std::pin::pin!(async { 20 }); @@ -298,8 +288,16 @@ impl fmt::Debug for Context<'_> { #[unstable(feature = "local_waker", issue = "118959")] #[derive(Debug)] pub struct ContextBuilder<'a> { - waker: Option<&'a Waker>, + waker: &'a Waker, local_waker: &'a LocalWaker, + // Ensure we future-proof against variance changes by forcing + // the lifetime to be invariant (argument-position lifetimes + // are contravariant while return-position lifetimes are + // covariant). + _marker: PhantomData &'a ()>, + // Ensure `Context` is `!Send` and `!Sync` in order to allow + // for future `!Send` and / or `!Sync` fields. + _marker2: PhantomData<*mut ()>, } impl<'a> ContextBuilder<'a> { @@ -310,23 +308,7 @@ impl<'a> ContextBuilder<'a> { pub const fn from_waker(waker: &'a Waker) -> Self { // SAFETY: LocalWaker is just Waker without thread safety let local_waker = unsafe { transmute(waker) }; - Self { waker: Some(waker), local_waker } - } - - /// Create a ContextBuilder from a LocalWaker. - #[inline] - #[rustc_const_unstable(feature = "const_waker", issue = "102012")] - #[unstable(feature = "local_waker", issue = "118959")] - pub const fn from_local_waker(local_waker: &'a LocalWaker) -> Self { - Self { local_waker, waker: None } - } - - /// This field is used to set the value of the waker on `Context`. - #[inline] - #[rustc_const_unstable(feature = "const_waker", issue = "102012")] - #[unstable(feature = "local_waker", issue = "118959")] - pub const fn waker(self, waker: &'a Waker) -> Self { - Self { waker: Some(waker), ..self } + Self { waker: waker, local_waker, _marker: PhantomData, _marker2: PhantomData } } /// This method is used to set the value for the local waker on `Context`. @@ -342,52 +324,8 @@ impl<'a> ContextBuilder<'a> { #[unstable(feature = "local_waker", issue = "118959")] #[rustc_const_unstable(feature = "const_waker", issue = "102012")] pub const fn build(self) -> Context<'a> { - let ContextBuilder { waker, local_waker } = self; - Context { waker, local_waker, _marker: PhantomData, _marker2: PhantomData } - } -} - -/// Construct a [`ContextBuilder`] from a [`Context`]. This is useful for -/// overriding values from a context. -/// -/// # Examples -/// An example of a future that allows to set a [`Waker`] on Context if none was defined. -/// This can be used to await futures that require a [`Waker`] even if the runtime does not -/// support [`Waker`]. -/// ```rust -/// #![feature(noop_waker, local_waker)] -/// use std::task::{Waker, ContextBuilder}; -/// use std::future::{poll_fn, Future}; -/// use std::pin::pin; -/// -/// async fn with_waker(f: F, waker: &Waker) -> F::Output -/// where -/// F: Future -/// { -/// let mut f = pin!(f); -/// poll_fn(move |cx| { -/// let has_waker = cx.try_waker().is_some(); -/// if has_waker { -/// return f.as_mut().poll(cx); -/// } -/// -/// let mut cx = ContextBuilder::from(cx) -/// .waker(&waker) -/// .build(); -/// f.as_mut().poll(&mut cx) -/// }).await -/// } -/// -/// # async fn __() { -/// with_waker(async { /* ... */ }, &Waker::noop()).await; -/// # } -/// ``` -#[unstable(feature = "local_waker", issue = "118959")] -impl<'a> From<&mut Context<'a>> for ContextBuilder<'a> { - #[inline] - fn from(value: &mut Context<'a>) -> Self { - let Context { waker, local_waker, _marker, _marker2 } = *value; - ContextBuilder { waker, local_waker } + let ContextBuilder { waker, local_waker, _marker, _marker2 } = self; + Context { waker, local_waker, _marker, _marker2 } } } @@ -598,8 +536,7 @@ impl fmt::Debug for Waker { /// Implements [`Clone`], but neither [`Send`] nor [`Sync`]; therefore, a local waker may /// not be moved to other threads. In general, when deciding to use wakers or local wakers, /// local wakers are preferable unless the waker needs to be sent across threads. This is because -/// wakers can incur in additional cost related to memory synchronization, and not all executors -/// may support wakers. +/// wakers can incur in additional cost related to memory synchronization. /// /// Note that it is preferable to use `local_waker.clone_from(&new_waker)` instead /// of `*local_waker = new_waker.clone()`, as the former will avoid cloning the waker @@ -736,8 +673,10 @@ impl LocalWaker { /// use std::future::Future; /// use std::task; /// + /// let waker = task::Waker::noop(); /// let local_waker = task::LocalWaker::noop(); - /// let mut cx = task::ContextBuilder::from_local_waker(&local_waker) + /// let mut cx = task::ContextBuilder::from_waker(&waker) + /// .local_waker(&local_waker) /// .build(); /// /// let mut future = Box::pin(async { 10 });