use std::{io, time::Duration};
use io_uring::{CompletionQueue, IoUring, Submitter, opcode, types};
use crate::driver::wire;
pub struct Ring {
inner: IoUring,
}
impl Ring {
pub(crate) fn new(uring: IoUring) -> Self {
Self { inner: uring }
}
pub(crate) fn submitter<'a>(&'a self) -> Submitter<'a> {
self.inner.submitter()
}
pub(crate) fn completion<'a>(&'a mut self) -> CompletionQueue<'a> {
self.inner.completion()
}
pub(in crate::driver) fn submission_len(&mut self) -> usize {
self.inner.submission().len()
}
pub(in crate::driver) fn is_full(&mut self) -> bool {
self.inner.submission().is_full()
}
pub(in crate::driver) fn has_submission(&mut self) -> bool {
!self.inner.submission().is_empty()
}
pub(in crate::driver) fn has_completion(&mut self) -> bool {
!self.inner.completion().is_empty()
}
pub(in crate::driver) fn submit_and_wait(&mut self, min_complete: u32) -> io::Result<()> {
self.inner.submit_and_wait(min_complete as usize)?;
Ok(())
}
pub(in crate::driver) fn submit(&mut self) -> io::Result<usize> {
let before = self.submission_len();
self.inner
.submit()
.map(|_| before.saturating_sub(self.submission_len()))
}
pub(in crate::driver) fn submit_with_timeout(
&mut self,
min_complete: u32,
duration: Duration,
) -> io::Result<()> {
let ts = types::Timespec::from(duration);
let args = types::SubmitArgs::new().timespec(&ts);
let want = min_complete as usize;
match self.inner.submitter().submit_with_args(want, &args) {
Ok(_) => Ok(()),
Err(e) if e.raw_os_error() == Some(libc::ETIME) => Ok(()),
Err(e) => Err(e),
}
}
pub(in crate::driver) fn try_push_arm(&mut self, sqe: io_uring::squeue::Entry) -> bool {
unsafe {
let mut sq = self.inner.submission();
sq.push(&sqe).is_ok()
}
}
pub(in crate::driver) fn push(&mut self, sqe: &io_uring::squeue::Entry) -> bool {
unsafe {
let mut sq = self.inner.submission();
sq.push(sqe).is_ok()
}
}
pub(in crate::driver) fn submit_cancel(&mut self, target_user_data: u64) {
let sqe = opcode::AsyncCancel::new(target_user_data)
.build()
.user_data(wire::ignore());
unsafe {
let mut sq = self.inner.submission();
if sq.push(&sqe).is_ok() {
return;
}
}
if let Err(e) = self.submit() {
panic!("dope invariant violated: cancel submit failed: {e}");
}
unsafe {
let mut sq = self.inner.submission();
if sq.push(&sqe).is_err() {
panic!("dope invariant violated: cancel SQE enqueue failed after submit");
}
}
}
}