pub fn poll_proceed(cx: &mut Context<'_>) -> Poll<RestoreOnPending>
Expand description
Decrements the task budget and returns Poll::Pending
if the budget is depleted.
This indicates that the task should yield to the scheduler. Otherwise, returns
RestoreOnPending
which can be used to commit the budget consumption.
The returned RestoreOnPending
will revert the budget to its former
value when dropped unless RestoreOnPending::made_progress
is called. It is the caller’s responsibility to do so when it was able to
make progress after the call to poll_proceed
.
Restoring the budget automatically ensures the task can try to make progress in some other
way.
Note that RestoreOnPending
restores the budget as it was before poll_proceed
.
Therefore, if the budget is further adjusted between when poll_proceed
returns and
RestoreOnPending
is dropped, those adjustments are erased unless the caller indicates
that progress was made.
§Examples
This example shows a simple countdown latch that uses poll_proceed
to participate in
cooperative scheduling.
use std::future::{Future};
use std::pin::Pin;
use std::task::{ready, Context, Poll, Waker};
use tokio::task::coop;
struct CountdownLatch<T> {
counter: usize,
value: Option<T>,
waker: Option<Waker>
}
impl<T> CountdownLatch<T> {
fn new(value: T, count: usize) -> Self {
CountdownLatch {
counter: count,
value: Some(value),
waker: None
}
}
fn count_down(&mut self) {
if self.counter <= 0 {
return;
}
self.counter -= 1;
if self.counter == 0 {
if let Some(w) = self.waker.take() {
w.wake();
}
}
}
}
impl<T> Future for CountdownLatch<T> {
type Output = T;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
// `poll_proceed` checks with the runtime if this task is still allowed to proceed
// with performing work.
// If not, `Pending` is returned and `ready!` ensures this function returns.
// If we are allowed to proceed, coop now represents the budget consumption
let coop = ready!(coop::poll_proceed(cx));
// Get a mutable reference to the CountdownLatch
let this = Pin::get_mut(self);
// Next we check if the latch is ready to release its value
if this.counter == 0 {
let t = this.value.take();
// The latch made progress so call `made_progress` to ensure the budget
// is not reverted.
coop.made_progress();
Poll::Ready(t.unwrap())
} else {
// If the latch is not ready so return pending and simply drop `coop`.
// This will restore the budget making it available again to perform any
// other work.
this.waker = Some(cx.waker().clone());
Poll::Pending
}
}
}
impl<T> Unpin for CountdownLatch<T> {}