Course contentsShow
← Rust
Lesson 1158 of 1,91010. Concurrency PrimitivesFree lesson

Poll-Based Execution State Machines

You will learn how the runtime drives progress through polling mechanisms.

In this lesson, you will learn how Rust’s async runtime drives progress by treating every Future as a manual state machine that must be explicitly polled to reach completion.

The Mechanism of Progress

In synchronous code, a function runs from start to finish without interruption. In Rust’s async model, a Future is essentially an opaque state machine. When you write an async block, the compiler generates a struct representing every point where your code could pause (e.g., waiting for a socket or timer).

However, this state machine is "lazy." It does nothing on its own. It requires an external actor—the Executor—to drive it. This is where poll comes in.

The poll Contract

The Future trait defines a single poll method. When an executor calls poll, it asks the state machine: "Are you done yet?"

  1. Poll::Ready(val): The state machine has reached its final state and returned a value.
  2. Poll::Pending: The state machine hit an "await point" that isn't ready. Crucially, the future must register a Waker before returning Pending. This ensures that when the resource finally becomes available (like a network packet arriving), the system knows exactly which state machine to resume.

Consider this simplified mental model:

fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
    match self.state {
        State::Start => {
            if resource_ready() {
                self.state = State::Done;
                Poll::Ready(result)
            } else {
                // Register interest and yield control back to the runtime
                cx.waker().wake_by_ref(); 
                Poll::Pending
            }
        }
        State::Done => panic!("Polled after completion"),
    }
}

Why This Matters

By using a poll-based model, Rust avoids the overhead of allocating a dedicated thread stack for every single concurrent operation. Instead of blocking a thread until work is done, the executor polls the future, receives a Pending signal, and immediately moves on to poll a different task. When the original task is ready, the Waker notifies the executor, which places the task back on the "to-be-polled" queue.

This state machine approach transforms concurrency from a "waiting" problem into a "scheduling" problem, allowing thousands of tasks to coexist on a handful of hardware threads.

Key Takeaway: A Rust Future is a passive state machine that relies on an external executor to repeatedly call poll until it transitions into a Ready state.