Pure C io_uring TCP server using liburing. Built for benchmark comparison against zerg (C# io_uring).
- 1 acceptor thread — multishot accept, round-robin to N reactors via lock-free SPSC queue
- N reactor threads — each with its own io_uring (
SINGLE_ISSUER | DEFER_TASKRUN), provided buffer ring, and multishot recv - Synchronous handler — runs inline on the reactor thread, zero cross-thread signaling
All liburing static inline functions are fully inlined by gcc at -O2.
Requires liburing (liburing-dev on Debian/Ubuntu).
makeProduces:
rgzero— server binary (linked againstlibringzero.sowith$ORIGINrpath)libringzero.so— shared librarylibringzero.a— static library
./rgzero [reactor_count] # default: 12 reactorsListens on 0.0.0.0:8080. Stop with Ctrl+C or SIGTERM.
include/
constants.h — UD packing macros, ring/buffer tunables
queue.h — lock-free SPSC queue (acceptor → reactor fd handoff)
listener.h — TCP listen socket setup
connection.h — per-connection state, write buffering
reactor.h — reactor struct, event loop, provided buffer ring
acceptor.h — multishot accept loop
engine.h — thread orchestration (acceptor + N reactors)
ringzero.h — umbrella header
src/lib/
engine.c — spawn/join acceptor and reactor threads
acceptor.c — multishot accept, round-robin fd distribution
reactor.c — io_uring event loop (recv/send/cancel)
connection.c — write slab management, flush logic
listener.c — SO_REUSEADDR/PORT, nonblocking listen socket
src/app/
main.c — CLI, signal handling, plaintext HTTP handler
- Single syscall loop —
io_uring_submit_and_wait_timeoutsubmits + harvests in one kernel entry - Zero-copy recv — provided buffer rings (
io_uring_setup_buf_ring), kernel writes directly into pre-registered memory - Multishot recv — one SQE arms continuous receive, no re-arming per event
- Batch CQE processing —
io_uring_peek_batch_cqeharvests up to 4096 completions at once - User-data packing —
PACK_UD(kind, fd)encodes operation type + fd in 64 bits