diff --git a/library/core/src/task/mod.rs b/library/core/src/task/mod.rs index 3d6f4f5971a62..dad379622f7a9 100644 --- a/library/core/src/task/mod.rs +++ b/library/core/src/task/mod.rs @@ -13,3 +13,7 @@ pub use self::wake::{Context, RawWaker, RawWakerVTable, Waker}; mod ready; #[unstable(feature = "ready_macro", issue = "70922")] pub use ready::ready; + +mod yield_now; +#[unstable(feature = "task_yield_now", issue = "74331")] +pub use self::yield_now::{yield_now, YieldNow}; diff --git a/library/core/src/task/yield_now.rs b/library/core/src/task/yield_now.rs new file mode 100644 index 0000000000000..6eaab6efb2344 --- /dev/null +++ b/library/core/src/task/yield_now.rs @@ -0,0 +1,58 @@ +use crate::future::Future; +use crate::pin::Pin; +use crate::task::{Context, Poll}; + +/// Cooperatively gives up a timeslice to the executor. +/// +/// Calling this function calls move the currently executing future to the back +/// of the execution queue, making room for other futures to execute. This is +/// especially useful after running CPU-intensive operations inside a future. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// #![feature(task_yield_now)] +/// # async fn run() { +/// # +/// use core::task; +/// +/// task::yield_now().await; +/// # +/// # } +/// ``` +#[unstable(feature = "task_yield_now", issue = "74331")] +#[inline] +pub fn yield_now() -> YieldNow { + YieldNow { is_polled: false } +} + +/// Creates a future that yields back to the executor exactly once. +/// +/// This `struct` is created by the [`yield_now`] function. See its +/// documentation for more. +#[unstable(feature = "task_yield_now", issue = "74331")] +#[must_use = "futures do nothing unless you `.await` or poll them"] +#[derive(Debug)] +pub struct YieldNow { + is_polled: bool, +} + +#[unstable(feature = "task_yield_now", issue = "74331")] +impl Future for YieldNow { + type Output = (); + + // Most futures executors are implemented as a FIFO queue, so all this + // future does is re-schedule the future back to the end of the queue, + // giving room for other futures to progress. + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + if self.is_polled { + return Poll::Ready(()); + } + + self.is_polled = true; + cx.waker().wake_by_ref(); + Poll::Pending + } +} diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index b834361b750eb..3fd60e95c8823 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -307,6 +307,7 @@ #![feature(stdsimd)] #![feature(stmt_expr_attributes)] #![feature(str_internals)] +#![feature(task_yield_now)] #![feature(test)] #![feature(thread_local)] #![feature(toowned_clone_into)] @@ -478,11 +479,15 @@ pub mod task { #[doc(inline)] #[stable(feature = "futures_api", since = "1.36.0")] - pub use core::task::*; + pub use core::task::{Context, Poll, RawWaker, RawWakerVTable, Waker}; #[doc(inline)] #[unstable(feature = "wake_trait", issue = "69912")] - pub use alloc::task::*; + pub use alloc::task::Wake; + + #[doc(inline)] + #[unstable(feature = "task_yield_now", issue = "74331")] + pub use core::task::{yield_now, YieldNow}; } #[stable(feature = "futures_api", since = "1.36.0")]