Skip to main content

Module iouring

Module iouring 

Source
Expand description

Task execution and I/O on Linux io_uring.

Runner polls ordinary tasks and drives their I/O on a pool of Config::with_worker_threads workers, two by default, each with its own io_uring ring. The first worker runs on the calling thread and also polls the root.

A task woken while idle is first queued on the pool worker that woke it, and one woken during its poll is first requeued on its poller. Tasks spawned or woken from outside the pool, and tasks spawned on a worker with other work queued when the pool has more than one worker, go to the global queue that any worker takes from.

Each worker has a bounded run queue. A push into a full run queue sends its newest half and the new task to the global queue, or only the new task while another worker is stealing from it. Before parking, a worker with nothing to run can steal half of another worker’s queued tasks, rounded down, so a task queued alone behind a long poll waits for it.

Dedicated and blocking tasks each receive a supervised thread and io_uring ring. Their ordinary descendants execute on the pool. Task factories run synchronously on the thread that calls crate::Spawner::spawn.

Sockets, blobs, and pending I/O and sleep futures can move between workers. Registrations stay on their original worker without keeping it alive. If it closes, pending I/O futures return errors and pending sleeps panic when polled. crate::Blob::start_sync handles can be awaited on another thread, even after the original runner shuts down.

§Ownership

Workers own request, timer, and result progress. Each ordinary task has at most one runnable, which a queue or poller owns, and at most one poll of that task runs at a time. A queued task can move through overflow or stealing, and each run queue synchronizes its owner with the workers that steal from it. Each open serializes its syncs and durable writes across workers until their results are recorded. Forwarded results, mailboxes, the global queue, the task set, task handles, supervision, and metrics are also synchronized across threads.

§Storage

Failures while synchronizing blob contents, including during SYNC writes, are retained across opens of the blob, even after every handle is dropped. Creation failures are retained when the header is complete. Removing or recreating the blob clears its retained error. A new runtime instance starts without the error record and still requires normal storage recovery.

§Requirements and Progress

Linux 6.1 or newer is required for single-issuer rings with deferred task work. Task polls must return so their worker can service I/O and deadlines. I/O and sleeps stay registered on the worker that first polled them, so a poll that blocks one worker also delays their results for tasks that have moved elsewhere.

Each worker limits in-flight I/O according to RingConfig::size. A receive can occupy the last slot while a send needed to satisfy it waits to be submitted. Use deadlines or cancellation to break such dependencies.

§Shutdown

On shutdown, the runner rejects new tasks and I/O, aborts supervised tasks, and drains registered I/O before returning. The first poll registers an I/O request with its worker. Registered storage writes and syncs run to completion even if their futures are dropped while still queued. For pending reads and network operations, dropping the future or closing the worker requests cancellation.

Shutdown waits for all workers to finish runtime cleanup and failure publication, with no timeout. No pool worker closes its mailbox or io_uring ring until every pool task’s future has been dropped, though dedicated and blocking tasks may still run and find a pool worker closed. Native thread-local destructors may run after the runner returns.

§Examples

use commonware_runtime::{Runner as _, Spawner, Supervisor, iouring};

iouring::Runner::default().start(|context| async move {
    let child = context.child("worker").spawn(|_| async { 42 });
    assert_eq!(child.await.unwrap(), 42);
});

Structs§

Config
Configuration for the native io_uring runtime.
Context
Runtime capabilities and supervision context for the current task.
RingConfig
Configuration of each worker’s io_uring instance and operation timing wheel.
Runner
Native io_uring runner executing ordinary tasks on a pool of workers, the first on its calling thread.
SpinnerConfig
Spinner configuration. Values are in microseconds.