#![no_std]
use core::{ptr::NonNull, time::Duration};
use rustix::{
io::{Errno, Result},
io_uring::{io_uring_params, Timespec},
};
use sys::io_uring;
mod sys;
pub struct IoRing {
ring: io_uring,
}
pub use rustix::{
fd::RawFd,
io_uring::{
addr3_struct, addr_len_struct, addr_or_splice_off_in_union, buf_union, cmd_op_struct,
io_uring_ptr, io_uring_user_data, ioprio_union, len_union, off_or_addr2_union,
op_flags_union, splice_fd_in_or_file_index_union, Advice, AtFlags, IoringAcceptFlags,
IoringAsyncCancelFlags, IoringCqeFlags, IoringFsyncFlags, IoringMsgringCmds,
IoringMsgringFlags, IoringOp, IoringPollFlags, IoringRecvFlags, IoringSendFlags,
IoringSqeFlags, IoringTimeoutFlags, OFlags, ReadWriteFlags, RecvFlags, RenameFlags,
SendFlags, SocketFlags, SpliceFlags,
},
};
pub use sys::{io_uring_cqe, io_uring_sqe};
impl IoRing {
pub fn new(entries: u32) -> Result<IoRing> {
unsafe {
let mut ring = core::mem::zeroed::<io_uring>();
let mut p = core::mem::zeroed::<io_uring_params>();
to_result(sys::io_uring_queue_init_params(entries, &mut ring, &mut p))?;
Ok(IoRing { ring })
}
}
pub unsafe fn push(&mut self, op: io_uring_sqe) -> Result<()> {
let Some(sqe) = self.get_sqe() else {
return Err(Errno::AGAIN);
};
sqe.as_ptr().write(op);
Ok(())
}
pub fn submit_and_wait(&mut self, timeout: Duration) -> Result<io_uring_cqe> {
unsafe {
let mut cqe = core::ptr::null_mut();
let mut ts = Timespec {
tv_sec: timeout.as_secs() as _,
tv_nsec: timeout.subsec_nanos() as _,
};
to_result(sys::io_uring_submit_and_wait_timeout(
&mut self.ring,
&mut cqe,
1,
&mut ts,
core::ptr::null_mut(),
))?;
let cqe = cqe.read();
sys::io_uring_cq_advance(&mut self.ring, 1);
Ok(cqe)
}
}
fn get_sqe(&mut self) -> Option<NonNull<io_uring_sqe>> {
unsafe { NonNull::new(sys::io_uring_get_sqe(&mut self.ring)) }
}
}
impl Drop for IoRing {
fn drop(&mut self) {
unsafe { sys::io_uring_queue_exit(&mut self.ring) }
}
}
fn to_result(code: i32) -> Result<u32> {
if code.is_negative() {
Err(Errno::from_raw_os_error(-code))
} else {
Ok(code as _)
}
}