Skip to main content

Crate simoom_rt

Crate simoom_rt 

Source
Expand description

simoom runtime: one event loop per core, timer wheel, buffer pools, cross-thread wakeups, offload pool.

§Model

  • One loop thread per core, shared-nothing. Each loop owns an I/O driver (simoom_sys::driver::Driver: epoll or io_uring on Linux, IOCP on Windows, kqueue on macOS), a buffer pool (pool::BufPool), a timer wheel (timer::TimerWheel) and its connections. Nothing on the hot path is shared between loops.
  • Completion style. The driver receives into pooled buffers and sends owned buffers; a connection sees bytes in and hands bytes out. Readiness is never exposed.
  • An idle connection holds no buffer. Buffers are lent to the driver, taken only when data arrives, and returned to the pool as soon as a handler has consumed the data and the reply is written.
  • Accepting. Linux: one SO_REUSEPORT listener per loop. Windows: one listener with a queue of AcceptEx calls on loop 0, which hands connections to the less busy of two loops. macOS: one shared listener, handed out the same way.
  • UDP. One endpoint per loop (SO_REUSEPORT sockets on Linux; loop 0 elsewhere) with batched receive and send, GRO/GSO, ECN and packet info, for QUIC.
  • Offload. Blocking work goes to a bounded shared pool (offload::OffloadPool) with CoDel admission; results come back to the connection’s loop as messages.
  • Caps and backpressure. Connection caps (total and per loop: over the cap a connection is accepted and closed at once), a cap on unconsumed input per connection, and write high/low-water marks that pause and resume reading.
  • Graceful stop with a deadline (RuntimeHandle::stop).

§Driving a protocol

Protocol crates are sans-io: they take received bytes and produce bytes to send. The glue is a Connection per connection, created by an Acceptor:

use simoom_rt::{Connection, ConnInfo, Ctx, Runtime};

struct Echo;
impl Connection for Echo {
    fn on_data(&mut self, cx: &mut Ctx<'_>, data: &[u8]) -> usize {
        let mut out = cx.buffer(data.len()); // pooled
        out.extend_from_slice(data);
        cx.send(out); // written at the end of the loop turn, batched with other output
        data.len()    // consumed everything: the input buffer goes back to the pool
    }
}

let rt = Runtime::builder()
    .threads(0) // one loop per CPU
    .listen("127.0.0.1:8080", |_: &ConnInfo| Some(Box::new(Echo) as Box<dyn Connection>))
    .start()
    .unwrap();
println!("listening on {:?}", rt.local_addrs());
rt.stop(std::time::Duration::from_secs(5));
rt.join();

UDP protocols (QUIC) implement Endpoint, created per loop by a UdpService.

Modules§

offload
A bounded, shared worker pool for blocking work (the M/M/c side of the hybrid design).
pool
Per-loop buffer pool in size classes.
timer
A hierarchical timing wheel (Varghese and Lauck, SOSP 1987).

Structs§

Builder
Builds and starts a runtime. See crate::Runtime::builder.
Config
Runtime settings. Config::default() suits a server.
ConnHandle
A handle to one connection, usable from any thread. Messages to a closed connection are dropped.
ConnInfo
What the runtime knows about a new connection when it asks an Acceptor for a handler.
Ctx
What a Connection callback can do: send, close, pause, set timers, reach other threads.
DriverConfig
Driver settings. The defaults suit a server loop.
DriverStats
System calls and events counted by a driver (plain counters; read them on the loop thread).
EndpointHandle
A handle to a UDP endpoint, usable from any thread.
ListenOptions
Options for Socket::tcp_listen.
LoopCtx
Access to a loop from a task run with LoopHandle::run.
LoopHandle
A handle to one loop, usable from any thread: run closures on the loop thread.
LoopSnapshot
Counters of one loop, as last published by it (once per loop turn).
RecvMeta
What the OS reported about one received datagram (or one GRO batch of datagrams).
Runtime
Entry point: Runtime::builder().
RuntimeHandle
A running runtime. Dropping it stops the runtime at once (no grace) and waits for its threads; call RuntimeHandle::stop and RuntimeHandle::join for a graceful stop.
Socket
An owned, non-blocking socket. Closed on drop.
Stats
Runtime counters.
Transmit
One datagram (or, with segment_size, a GSO batch of datagrams) to send.
UdpCtx
What an Endpoint callback can do.
UdpInfo
Information for creating a UDP endpoint on a loop.
UdpOptions
Options for Socket::udp_bind.

Enums§

Backend
Which I/O back end a driver uses.
CloseReason
Why a connection was closed, passed to Connection::on_close.
OutBuf
A buffer to send: owned (returned by Event::Sent for reuse) or static.

Traits§

Acceptor
Creates a Connection for each accepted socket. Shared by every loop, so it must be Send + Sync; any closure Fn(&ConnInfo) -> Option<Box<dyn Connection>> is one.
Connection
A connection’s protocol state machine. It lives on one loop thread and is called only from there, so it need not be Send. A sans-io protocol crate sits behind it: received bytes go in through Connection::on_data, bytes to send go out through Ctx::send.
Endpoint
A UDP endpoint (for QUIC, a whole connection table) on one loop.
UdpService
Creates the per-loop Endpoint of a UDP binding. On Linux every loop gets its own SO_REUSEPORT socket and endpoint; elsewhere only loop 0 does.

Type Aliases§

Message
A value sent to a connection or endpoint from another thread (crate::ConnHandle, crate::EndpointHandle, Ctx::offload). Downcast it with msg.downcast::<T>().