Repository: tokio-rs/tokio
File: tokio/src/runtime/mod.rs (Rust)

Code before:
//! [`Builder::enable_io`]: crate::runtime::Builder::enable_io
//! [`Builder::enable_time`]: crate::runtime::Builder::enable_time
//! [`Builder::enable_all`]: crate::runtime::Builder::enable_all
//!
//! # Detailed runtime behavior
//!
//! This section gives more details into how the Tokio runtime will schedule
//! tasks for execution.
//!
//! At its most basic level, a runtime has a collection of tasks that need to be
//! polled. It will repeatedly remove a task from that collection and poll it.
//! When the collection is empty, the thread will go to sleep until a task is
//! added to the collection.
//!
//! However, the above is not sufficient to guarantee a well-behaved runtime.
//! For example, the runtime might have a single task that is always ready to be
//! polled, and poll that task every time. This is a problem because it starves
//! other tasks by not polling them. To solve this, Tokio provides the following
//! fairness guarantee:
//!
//! > Under the following two assumptions:
//! >
//! > * There is some number `MAX_TASKS` such that the total number of tasks on
//! >   the runtime never exceeds `MAX_TASKS`.
//! > * There is some number `MAX_POLL` such that calling [`poll`] on any task
//! >   spawned on the runtime returns within `MAX_POLL` time units.
//! >
//! > Then, it is guaranteed that tasks are scheduled fairly, that is, there is
//! > some number `MAX_DELAY` such that when a task becomes ready, it will be
//! > polled by the runtime within `MAX_DELAY` time units.
//!
//! Other than the above fairness guarantee, there is no guarantee about the
//! order in which tasks are polled. There is also no guarantee that the runtime
//! is equally fair to all tasks. For example, if the runtime has two tasks A
//! and B that are both ready, then the runtime may poll A five times before it
//! polls B. This is the case even if A yields using [`yield_now`]. All that is
//! guaranteed is that it will poll B eventually.
//!
//! Normally, tasks are polled only if they have notified the runtime by waking
//! their waker. However, this is not guaranteed, and Tokio may poll tasks that
//! have not notified the runtime under some circumstances. This is called a
//! spurious wakeup.
//!
//! ## IO and timers
//!
//! Beyond just polling tasks, the runtime must also manage IO resources and
//! timers. It does this by periodically checking whether there are any IO
//! resources or timers that are ready, and notifying the relevant task so that
//! it will be polled.
//!
//! These checks are performed periodically between polling tasks. Under the

Review comment (suggestion):
This section a bit confusing I think. Specifically, `MAX_TASKS` and `MAX_POLL` time unit are entirely controlled by the user. I might rephrase this to make it a bit more explicit that the user controls these. And if you move away from "poll" as a term in these docs, you could probably rephrase max poll as something like "max duration a task executes before yielding back to the runtime".

Code after:
//! [`Builder::enable_io`]: crate::runtime::Builder::enable_io
//! [`Builder::enable_time`]: crate::runtime::Builder::enable_time
//! [`Builder::enable_all`]: crate::runtime::Builder::enable_all
//!
//! # Detailed runtime behavior
//!
//! This section gives more details into how the Tokio runtime will schedule
//! tasks for execution.
//!
//! At its most basic level, a runtime has a collection of tasks that need to be
//! scheduled. It will repeatedly remove a task from that collection and
//! schedule it (by calling [`poll`]). When the collection is empty, the thread
//! will go to sleep until a task is added to the collection.
//!
//! However, the above is not sufficient to guarantee a well-behaved runtime.
//! For example, the runtime might have a single task that is always ready to be
//! scheduled, and schedule that task every time. This is a problem because it
//! starves other tasks by not scheduling them. To solve this, Tokio provides
//! the following fairness guarantee:
//!
//! > If the total number of tasks does not grow without bound, and no task is
//! > [blocking the thread], then it is guaranteed that tasks are scheduled
//! > fairly.
//!
//! Or, more formally:
//!
//! > Under the following two assumptions:
//! >
//! > * There is some number `MAX_TASKS` such that the total number of tasks on
//! >   the runtime at any specific point in time never exceeds `MAX_TASKS`.
//! > * There is some number `MAX_SCHEDULE` such that calling [`poll`] on any
//! >   task spawned on the runtime returns within `MAX_SCHEDULE` time units.
//! >
//! > Then, there is some number `MAX_DELAY` such that when a task is woken, it
//! > will be scheduled by the runtime within `MAX_DELAY` time units.
//!
//! (Here, `MAX_TASKS` and `MAX_SCHEDULE` can be any number and the user of
//! the runtime may choose them. The `MAX_DELAY` number is controlled by the
//! runtime, and depends on the value of `MAX_TASKS` and `MAX_SCHEDULE`.)
//!
//! Other than the above fairness guarantee, there is no guarantee about the
//! order in which tasks are scheduled. There is also no guarantee that the
//! runtime is equally fair to all tasks. For example, if the runtime has two
//! tasks A and B that are both ready, then the runtime may schedule A five
//! times before it schedules B. This is the case even if A yields using
//! [`yield_now`]. All that is guaranteed is that it will schedule B eventually.
//!
//! Normally, tasks are scheduled only if they have been woken by calling
//! [`wake`] on their waker. However, this is not guaranteed, and Tokio may
//! schedule tasks that have not been woken under some circumstances. This is
//! called a spurious wakeup.