Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
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.
  • Loading branch information
tvallotton committed Jan 20, 2024
commit 038c6e046c450082ebd087336d9b11979e0dd4f3
16 changes: 10 additions & 6 deletions library/alloc/src/task.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,14 +173,16 @@ fn raw_waker<W: Wake + Send + Sync + 'static>(waker: Arc<W>) -> 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;
Expand Down Expand Up @@ -225,10 +227,12 @@ fn raw_waker<W: Wake + Send + Sync + 'static>(waker: Arc<W>) -> RawWaker {
/// // we exit, since there are no more tasks remaining on the queue
/// return;
/// };
/// let waker = Waker::noop();
/// // cast the Rc<Task> 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
Expand Down
99 changes: 18 additions & 81 deletions library/core/src/task/wake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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]
Expand All @@ -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")]
Expand All @@ -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 });
Expand All @@ -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<fn(&'a ()) -> &'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> {
Expand All @@ -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`.
Expand All @@ -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: 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 }
}
}

Expand Down Expand Up @@ -600,8 +538,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
Expand Down Expand Up @@ -738,7 +675,7 @@ impl LocalWaker {
/// use std::future::Future;
/// use std::task::{ContextBuilder, LocalWaker};
///
/// let mut cx = task::ContextBuilder::new()
/// let mut cx = task::ContextBuilder::from_waker(Waker::noop())
/// .local_waker(LocalWaker::noop())
/// .build();
///
Expand Down