pub struct IoUring { /* private fields */ }Expand description
A Linux io_uring instance: one submission ring + one completion ring.
Implementations§
Source§impl IoUring
impl IoUring
Sourcepub unsafe fn prep_read(
&mut self,
fd: i32,
buf: *mut u8,
len: u32,
user_data: u64,
) -> bool
pub unsafe fn prep_read( &mut self, fd: i32, buf: *mut u8, len: u32, user_data: u64, ) -> bool
Queue a read(fd) of len bytes into buf, tagged with user_data.
Returns false if the SQ is full.
§Safety
buf must point to len writable bytes and stay valid until the matching
completion is reaped.
Sourcepub unsafe fn prep_write(
&mut self,
fd: i32,
buf: *const u8,
len: u32,
user_data: u64,
) -> bool
pub unsafe fn prep_write( &mut self, fd: i32, buf: *const u8, len: u32, user_data: u64, ) -> bool
Queue a write(fd) of len bytes from buf, tagged with user_data.
Returns false if the SQ is full.
§Safety
buf must point to len readable bytes and stay valid until the matching
completion is reaped.
Sourcepub fn prep_recv_multishot(
&mut self,
fd: i32,
bgid: u16,
user_data: u64,
) -> bool
pub fn prep_recv_multishot( &mut self, fd: i32, bgid: u16, user_data: u64, ) -> bool
Queue a multishot recv(fd) that draws its destination buffer from
the provided-buffer group bgid (see IoUring::register_buf_ring): one
SQE re-fires a completion per arrival, the kernel picking + reporting a
buffer id each time, until it terminates (error / ENOBUFS, signalled by
crate::Completion::has_more returning false). No per-recv SQE, no read
buffer to keep alive. Returns false if the SQ is full.
Sourcepub unsafe fn prep_write_fixed(
&mut self,
slot: u32,
buf: *const u8,
len: u32,
user_data: u64,
) -> bool
pub unsafe fn prep_write_fixed( &mut self, slot: u32, buf: *const u8, len: u32, user_data: u64, ) -> bool
Same as Self::prep_write but addresses the destination by
registered-files slot index instead of raw fd. Sets
IOSQE_FIXED_FILE; the kernel skips its per-op fget/fput. Caller
must have populated slot via
crate::IoUring::update_file_slot.
§Safety
Same as prep_write.
Sourcepub fn prep_recv_multishot_fixed(
&mut self,
slot: u32,
bgid: u16,
user_data: u64,
) -> bool
pub fn prep_recv_multishot_fixed( &mut self, slot: u32, bgid: u16, user_data: u64, ) -> bool
Same as Self::prep_recv_multishot but addresses the source by
registered-files slot index instead of raw fd. Sets
IOSQE_FIXED_FILE | IOSQE_BUFFER_SELECT; the kernel skips its
per-op fget/fput. Caller must have populated slot via
crate::IoUring::update_file_slot.
Sourcepub fn prep_accept(&mut self, listen_fd: i32, user_data: u64) -> bool
pub fn prep_accept(&mut self, listen_fd: i32, user_data: u64) -> bool
Queue an accept on listen_fd; the accepted fd arrives as the
completion’s res (already O_NONBLOCK | O_CLOEXEC). Returns false if
the SQ is full.
Sourcepub unsafe fn prep_timeout(
&mut self,
ts: *const KernelTimespec,
user_data: u64,
) -> bool
pub unsafe fn prep_timeout( &mut self, ts: *const KernelTimespec, user_data: u64, ) -> bool
Queue a relative timeout: the completion (res = -ETIME) arrives once
ts elapses, or earlier with res = 0 / -ECANCELED if the ring shuts
down. Bounds a blocking IoUring::submit_and_wait the way a poller’s
wait-timeout would. Returns false if the SQ is full.
§Safety
ts must stay valid (not moved or dropped) until the matching
completion is reaped — the kernel reads it asynchronously.
Source§impl IoUring
impl IoUring
Sourcepub fn register_buf_ring(
&self,
entries: u16,
buf_size: u32,
bgid: u16,
) -> Result<ProvidedBufRing>
pub fn register_buf_ring( &self, entries: u16, buf_size: u32, bgid: u16, ) -> Result<ProvidedBufRing>
Register a provided-buffer ring of entries (power of two) buffers of
buf_size bytes each under group id bgid, for multishot
prep_recv_multishot. The kernel draws a buffer per arrival and
reports its id; the application recycles it via
ProvidedBufRing::recycle. The registration is auto-released when
the ring fd closes; the returned handle also unregisters + unmaps on
drop.
Sourcepub fn register_files_sparse(&self, nr: u32) -> Result<()>
pub fn register_files_sparse(&self, nr: u32) -> Result<()>
Register a sparse registered-files table of nr slots — empty
initially; slots are filled later via Self::update_file_slot and
referenced from SQEs by setting IOSQE_FIXED_FILE and putting the
slot index in the SQE’s fd field. The kernel skips the per-op
fget/fput fd-table lookup for any SQE that uses a fixed file.
Requires Linux 5.13+ for the rsrc-struct API. The table is
auto-released when the ring fd closes. The kernel rejects
nr > RLIMIT_NOFILE; callers that need >1024 slots must bump
ulimit themselves.
Call shape: IORING_REGISTER_FILES2 (#13) with
IoUringRsrcRegister { nr, flags: IORING_RSRC_REGISTER_SPARSE, .. }
nr_args = sizeof::<IoUringRsrcRegister>() = 32. There is no stand-alone “FILES_SPARSE” opcode in mainline.
Sourcepub fn update_file_slot(&self, index: u32, fd: i32) -> Result<()>
pub fn update_file_slot(&self, index: u32, fd: i32) -> Result<()>
Place fd into registered-files slot index, or unmap the slot if
fd < 0. After a successful call SQEs referencing IOSQE_FIXED_FILE
fd = indexwill skip the fd-table lookup. Cheaper than the full per-op fget/fput once amortised across many ops per conn.
Source§impl IoUring
impl IoUring
Sourcepub fn new(entries: u32) -> Result<IoUring>
pub fn new(entries: u32) -> Result<IoUring>
Create a ring sized for at least entries in-flight submissions.
Sourcepub fn new_sqpoll(
entries: u32,
idle_ms: u32,
cpu: Option<u32>,
) -> Result<IoUring>
pub fn new_sqpoll( entries: u32, idle_ms: u32, cpu: Option<u32>, ) -> Result<IoUring>
Create a ring backed by a kernel-side submission poll thread
(IORING_SETUP_SQPOLL). Submissions are reaped without an
io_uring_enter syscall on the steady state; when the SQ poll
thread parks (after idle_ms ms with no work), userland wakes it
via Self::submit_and_wait’s SQ_WAKEUP path.
cpu = Some(c) pins the kernel thread to CPU c via
IORING_SETUP_SQ_AFF. Costs 1 core at ~100% whenever traffic
flows; requires Linux 5.13+ (the version that dropped CAP_SYS_NICE
for SQPOLL).
Not suitable for kevy’s per-shard reactor. Each ring spawns
one kernel poll thread; in kevy’s shared-nothing layout N shards
would spawn N poll threads, each contending for the same cores
as the shard threads (measured 2–15× throughput regression on
the lx64 reference box, 10 shards on 16 cores — see
bench/PERF-ATTACK-LOG-2026-06-20.md attack D5). Reserved for
callers with a single-threaded reactor and an unallocated core
budget for the kernel poll thread.
Sourcepub fn submit_and_wait(&mut self, wait_nr: u32) -> Result<u32>
pub fn submit_and_wait(&mut self, wait_nr: u32) -> Result<u32>
Publish queued submissions and enter the kernel, optionally waiting for
wait_nr completions. Returns the number of SQEs consumed.
SQPOLL fast path: when the ring was constructed via
Self::new_sqpoll and the SQ poll thread is awake
(IORING_SQ_NEED_WAKEUP clear) and the caller doesn’t need to block
on completions (wait_nr == 0), we publish the tail and return
without any syscall — the kernel thread will reap submissions on
its next poll spin.
Sourcepub fn for_each_completion<F: FnMut(Completion)>(&mut self, f: F) -> u32
pub fn for_each_completion<F: FnMut(Completion)>(&mut self, f: F) -> u32
Reap every available completion, calling f for each; returns the count.