use std::io;
#[cfg(not(target_os = "linux"))]
compile_error!("Uringy only supports Linux");
#[cfg(target_os = "linux")]
pub(super) struct Uring {
io_uring: io_uring::IoUring,
}
#[cfg(target_os = "linux")]
const ASYNC_CANCELLATION: UserData = UserData(u64::MAX);
#[cfg(target_os = "linux")]
impl Uring {
pub(super) fn new() -> Self {
let mut builder = io_uring::IoUring::builder();
builder.setup_clamp(); let io_uring = builder.build(1024).unwrap();
Uring { io_uring }
}
pub(super) fn wait_for_completed_syscall(&mut self) {
self.io_uring.submit_and_wait(1).unwrap();
}
pub(super) fn process_cq(&mut self) -> Vec<(UserData, io::Result<u32>)> {
let mut results = vec![];
for cqe in self.io_uring.completion() {
if cqe.user_data() == ASYNC_CANCELLATION.0 {
continue;
}
let user_data = UserData(cqe.user_data());
let result = if cqe.result() >= 0 {
Ok(cqe.result() as u32)
} else {
Err(io::Error::from_raw_os_error(-cqe.result()))
};
results.push((user_data, result));
}
results
}
pub(super) fn cancel_syscall(&mut self, user_data: UserData) {
let sqe = io_uring::opcode::AsyncCancel::new(user_data.0).build();
self.issue_syscall(ASYNC_CANCELLATION, sqe);
}
pub(super) fn issue_syscall(&mut self, user_data: UserData, sqe: io_uring::squeue::Entry) {
let sqe = sqe.user_data(user_data.0);
let mut sq = self.io_uring.submission();
while sq.is_full() {
drop(sq); dbg!(self.io_uring.submit().unwrap()); sq = self.io_uring.submission();
}
unsafe { sq.push(&sqe).unwrap() }; }
}
#[repr(transparent)]
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub(super) struct UserData(pub(super) u64);