Skip to content

Commit 7e51b44

Browse files
authored
task: document non-guarantees of yield_now (#4091)
1 parent bd1e4aa commit 7e51b44

File tree

1 file changed

+49
-28
lines changed

1 file changed

+49
-28
lines changed

tokio/src/task/yield_now.rs

+49-28
Original file line numberDiff line numberDiff line change
@@ -2,37 +2,58 @@ use std::future::Future;
22
use std::pin::Pin;
33
use std::task::{Context, Poll};
44

5-
cfg_rt! {
6-
/// Yields execution back to the Tokio runtime.
7-
///
8-
/// A task yields by awaiting on `yield_now()`, and may resume when that
9-
/// future completes (with no output.) The current task will be re-added as
10-
/// a pending task at the _back_ of the pending queue. Any other pending
11-
/// tasks will be scheduled. No other waking is required for the task to
12-
/// continue.
13-
///
14-
/// See also the usage example in the [task module](index.html#yield_now).
15-
#[must_use = "yield_now does nothing unless polled/`await`-ed"]
16-
pub async fn yield_now() {
17-
/// Yield implementation
18-
struct YieldNow {
19-
yielded: bool,
20-
}
21-
22-
impl Future for YieldNow {
23-
type Output = ();
5+
/// Yields execution back to the Tokio runtime.
6+
///
7+
/// A task yields by awaiting on `yield_now()`, and may resume when that future
8+
/// completes (with no output.) The current task will be re-added as a pending
9+
/// task at the _back_ of the pending queue. Any other pending tasks will be
10+
/// scheduled. No other waking is required for the task to continue.
11+
///
12+
/// See also the usage example in the [task module](index.html#yield_now).
13+
///
14+
/// ## Non-guarantees
15+
///
16+
/// This function may not yield all the way up to the executor if there are any
17+
/// special combinators above it in the call stack. For example, if a
18+
/// [`tokio::select!`] has another branch complete during the same poll as the
19+
/// `yield_now()`, then the yield is not propagated all the way up to the
20+
/// runtime.
21+
///
22+
/// It is generally not guaranteed that the runtime behaves like you expect it
23+
/// to when deciding which task to schedule next after a call to `yield_now()`.
24+
/// In particular, the runtime may choose to poll the task that just ran
25+
/// `yield_now()` again immediately without polling any other tasks first. For
26+
/// example, the runtime will not drive the IO driver between every poll of a
27+
/// task, and this could result in the runtime polling the current task again
28+
/// immediately even if there is another task that could make progress if that
29+
/// other task is waiting for a notification from the IO driver.
30+
///
31+
/// In general, changes to the order in which the runtime polls tasks is not
32+
/// considered a breaking change, and your program should be correct no matter
33+
/// which order the runtime polls your tasks in.
34+
///
35+
/// [`tokio::select!`]: macro@crate::select
36+
#[must_use = "yield_now does nothing unless polled/`await`-ed"]
37+
#[cfg_attr(docsrs, doc(cfg(feature = "rt")))]
38+
pub async fn yield_now() {
39+
/// Yield implementation
40+
struct YieldNow {
41+
yielded: bool,
42+
}
2443

25-
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
26-
if self.yielded {
27-
return Poll::Ready(());
28-
}
44+
impl Future for YieldNow {
45+
type Output = ();
2946

30-
self.yielded = true;
31-
cx.waker().wake_by_ref();
32-
Poll::Pending
47+
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
48+
if self.yielded {
49+
return Poll::Ready(());
3350
}
34-
}
3551

36-
YieldNow { yielded: false }.await
52+
self.yielded = true;
53+
cx.waker().wake_by_ref();
54+
Poll::Pending
55+
}
3756
}
57+
58+
YieldNow { yielded: false }.await
3859
}

0 commit comments

Comments
 (0)