Function poll_proceed

Source
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> {}