use crate::error::{Error, Result};
use crate::sys;
use std::marker::PhantomData;
pub struct SubmissionQueue<'ring> {
ring: *mut sys::io_uring,
_phantom: PhantomData<&'ring mut sys::io_uring>,
}
impl<'ring> SubmissionQueue<'ring> {
pub(crate) fn new(ring: &'ring mut sys::io_uring) -> Self {
Self {
ring,
_phantom: PhantomData,
}
}
pub fn get_sqe(&mut self) -> Option<&mut sys::io_uring_sqe> {
let sqe = unsafe { sys::io_uring_get_sqe(self.ring) };
if sqe.is_null() {
None
} else {
Some(unsafe { &mut *sqe })
}
}
pub fn get_sqe_or_err(&mut self) -> Result<&mut sys::io_uring_sqe> {
self.get_sqe().ok_or(Error::SubmissionQueueFull)
}
pub fn submit(&mut self) -> Result<usize> {
let ret = unsafe { sys::io_uring_submit(self.ring) };
if ret < 0 {
Err(crate::error::from_ret_code(ret).into())
} else {
Ok(ret as usize)
}
}
pub fn submit_and_wait(&mut self, wait_nr: u32) -> Result<usize> {
let ret = unsafe { sys::io_uring_submit_and_wait(self.ring, wait_nr) };
if ret < 0 {
Err(crate::error::from_ret_code(ret).into())
} else {
Ok(ret as usize)
}
}
pub fn space_left(&self) -> u32 {
unsafe {
let sq = &(*self.ring).sq;
let head = *sq.khead;
let tail = sq.sqe_tail;
sq.ring_entries - (tail.wrapping_sub(head))
}
}
pub fn is_full(&self) -> bool {
self.space_left() == 0
}
}
pub struct CompletionQueue<'ring> {
ring: *mut sys::io_uring,
_phantom: PhantomData<&'ring mut sys::io_uring>,
}
impl<'ring> CompletionQueue<'ring> {
pub(crate) fn new(ring: &'ring mut sys::io_uring) -> Self {
Self {
ring,
_phantom: PhantomData,
}
}
pub fn wait_cqe(&mut self) -> Result<Cqe<'_>> {
let mut cqe: *mut sys::io_uring_cqe = std::ptr::null_mut();
let ret =
unsafe { sys::io_uring_wait_cqe_timeout(self.ring, &mut cqe, std::ptr::null_mut()) };
if ret < 0 {
Err(crate::error::from_ret_code(ret).into())
} else if cqe.is_null() {
Err(Error::CompletionQueueEmpty)
} else {
Ok(Cqe {
cqe,
ring: self.ring,
_phantom: PhantomData,
})
}
}
pub fn peek_cqe(&mut self) -> Option<Cqe<'_>> {
let mut cqe: *mut sys::io_uring_cqe = std::ptr::null_mut();
let ret = unsafe { sys::io_uring_peek_cqe(self.ring, &mut cqe) };
if ret < 0 || cqe.is_null() {
None
} else {
Some(Cqe {
cqe,
ring: self.ring,
_phantom: PhantomData,
})
}
}
pub fn peek_batch(&mut self, cqes: &mut [*mut sys::io_uring_cqe]) -> usize {
let count = cqes.len() as u32;
unsafe { sys::io_uring_peek_batch_cqe(self.ring, cqes.as_mut_ptr(), count) as usize }
}
}
pub struct Cqe<'ring> {
cqe: *mut sys::io_uring_cqe,
ring: *mut sys::io_uring,
_phantom: PhantomData<&'ring mut sys::io_uring_cqe>,
}
impl<'ring> Cqe<'ring> {
pub fn user_data(&self) -> u64 {
unsafe { (*self.cqe).user_data }
}
pub fn result(&self) -> i32 {
unsafe { (*self.cqe).res }
}
pub fn flags(&self) -> u32 {
unsafe { (*self.cqe).flags }
}
pub fn is_success(&self) -> bool {
self.result() >= 0
}
pub fn into_result(self) -> std::io::Result<i32> {
let res = self.result();
if res < 0 {
Err(crate::error::from_ret_code(res))
} else {
Ok(res)
}
}
}
impl Drop for Cqe<'_> {
fn drop(&mut self) {
unsafe {
sys::io_uring_cqe_seen(self.ring, self.cqe);
}
}
}
#[cfg(test)]
mod tests {
#[test]
fn test_queue_operations() {
}
}