Skip to main content

Crate giong

Crate giong 

Source
Expand description

§giong

A thread-per-core async runtime for Linux, built directly on io_uring.

Named after Thánh Gióng, the child of Vietnamese legend who lay silent for three years and then rose a giant: giong costs next to nothing while idle and uses every core the moment load arrives.

§Design

  • Thread-per-core, shared-nothing. Every worker thread owns its own io_uring, task queue, timers and buffer pool. Tasks never migrate, so futures need not be Send and the hot path has no locks and no atomics beyond a waker flag.
  • Completion-based I/O with batching. Everything a tick produces — reads, writes, accepts, closes, cancellations — reaches the kernel in a single io_uring_enter, which also returns every completion that is ready.
  • Multishot accept and receive with kernel-provided buffers: one submission per listener / connection, no buffer pinned by idle connections.
  • One ring for everything. TCP, UDP and Unix sockets (net) and files (fs) all go through the worker’s io_uring. File I/O needs no pool of blocking threads.
  • A latency dial. Builder::spin_before_park lets a worker watch its ring instead of sleeping, for services where microseconds matter more than an idle core.
  • Cancellation safety. Dropping an I/O future never frees memory the kernel may still write to; ownership of the buffer moves to the driver until the kernel confirms.

§Example

use giong::net::TcpListener;

fn main() -> std::io::Result<()> {
    giong::Builder::new().shutdown_on_signals(true).build()?.run(|_worker| async {
        let listener = TcpListener::bind("0.0.0.0:8080").expect("bind");
        while let Some(Ok(stream)) = giong::until_shutdown(listener.accept()).await {
            giong::spawn(async move {
                loop {
                    let Ok(data) = stream.recv().await else { return };
                    if data.is_empty() {
                        return; // peer closed
                    }
                    let reply = data.to_vec();
                    drop(data); // give the buffer back to the pool
                    if stream.write_all(reply).await.0.is_err() {
                        return;
                    }
                }
            });
        }
    })
}

§Requirements

Linux 6.0 or newer (6.1+ recommended). giong does not build on other platforms.

Modules§

fs
Files on io_uring.
net
TCP, UDP and Unix sockets on io_uring.
sync
Message passing between tasks — on the same worker, across workers, or from threads outside the runtime.
time
Timers: sleep, sleep_until and timeout.

Structs§

Builder
Configures and starts a runtime.
Handle
A cloneable, thread-safe handle to a runtime.
JoinHandle
A handle to a spawned task. Awaiting it yields the task’s output.
RecvBuf
Bytes received by TcpStream::recv.
Runtime
A configured, not yet running, thread-per-core runtime.
ShutdownSignal
Future returned by shutdown_signal.

Enums§

JoinError
Why a task did not produce a value.

Traits§

IoBuf
A buffer that can be handed to the kernel for the duration of a write.
IoBufMut
A buffer the kernel may write into (see IoBuf for the ownership model).

Functions§

block_on
Runs a future to completion on the current thread with a single-worker runtime using the default configuration.
handle
A handle to the runtime the current task is running on.
is_shutting_down
true once shutdown_signal would resolve on the current worker: a shutdown has been requested, or the worker is draining its remaining tasks. A cheap check for loops that are busy rather than waiting.
shutdown_signal
Resolves once a shutdown of the current runtime has been requested, via Handle::shutdown or a signal (see Builder::shutdown_on_signals), or once the current worker’s main future has completed and the worker is draining its remaining tasks (see Builder::shutdown_grace).
spawn
Spawns a task onto the current worker thread.
until_shutdown
Runs fut until it completes or a shutdown is requested, whichever comes first. Returns None if the shutdown won.
worker_id
Index of the worker the current task is running on (0..workers).
yield_now
Yields to the executor, letting other tasks and pending I/O make progress.