Skip to main content

IoUring

Struct IoUring 

Source
pub struct IoUring { /* private fields */ }
Expand description

A Linux io_uring instance: one submission ring + one completion ring.

Implementations§

Source§

impl IoUring

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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

pub fn prep_nop(&mut self, user_data: u64) -> bool

Queue a no-op tagged with user_data (used to prove the round-trip). Returns false if the SQ is full.

Source§

impl IoUring

Source

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.

Source

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.
Source

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 = index will skip the fd-table lookup. Cheaper than the full per-op fget/fput once amortised across many ops per conn.
Source§

impl IoUring

Source

pub fn new(entries: u32) -> Result<IoUring>

Create a ring sized for at least entries in-flight submissions.

Source

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.

Source

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.

Source

pub fn for_each_completion<F: FnMut(Completion)>(&mut self, f: F) -> u32

Reap every available completion, calling f for each; returns the count.

Trait Implementations§

Source§

impl Drop for IoUring

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

fn pin_drop(self: Pin<&mut Self>)

🔬This is a nightly-only experimental API. (pin_ergonomics)
Execute the destructor for this type, but different to Drop::drop, it requires self to be pinned. Read more
Source§

impl Send for IoUring

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.