use core::mem;
use std::os::fd::RawFd;
use crate::{bindings, Entry, SqeFlags};
macro_rules! opcode {
(@type $name:ty ) => {
$name
};
(
$( #[$outer:meta] )*
pub struct $name:ident {
$( #[$new_meta:meta] )*
$( $field:ident : { $( $tnt:tt )+ } ),*
$(,)?
;;
$(
$( #[$opt_meta:meta] )*
$opt_field:ident : $opt_tname:ty = $default:expr
),*
$(,)?
}
pub const CODE = $opcode:expr;
$( #[$build_meta:meta] )*
pub fn build($self:ident) -> $entry:ty $build_block:block
) => {
$( #[$outer] )*
pub struct $name {
$( $field : opcode!(@type $( $tnt )*), )*
$( $opt_field : $opt_tname, )*
}
impl $name {
$( #[$new_meta] )*
#[inline]
pub fn new($( $field : $( $tnt )* ),*) -> Self {
$name {
$( $field: $field.into(), )*
$( $opt_field: $default, )*
}
}
pub const CODE: u8 = $opcode as _;
$(
$( #[$opt_meta] )*
#[inline]
pub const fn $opt_field(mut self, $opt_field: $opt_tname) -> Self {
self.$opt_field = $opt_field;
self
}
)*
$( #[$build_meta] )*
#[inline]
pub fn build($self) -> $entry $build_block
}
}
}
#[inline(always)]
fn sqe_zeroed() -> bindings::io_uring_sqe {
unsafe { mem::zeroed() }
}
opcode! {
#[derive(Debug)]
pub struct Nop { ;; }
pub const CODE = bindings::io_uring_op_IORING_OP_NOP;
pub fn build(self) -> Entry {
let Nop {} = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = -1;
Entry(sqe)
}
}
opcode! {
#[derive(Debug)]
pub struct Readv {
fd: { RawFd },
iovec: { *const libc::iovec },
len: { u32 },
;;
ioprio: u16 = 0,
offset: u64 = 0,
rw_flags: i32 = 0,
buf_group: u16 = 0
}
pub const CODE = bindings::io_uring_op_IORING_OP_READV;
pub fn build(self) -> Entry {
let Readv {
fd,
iovec, len, offset,
ioprio, rw_flags,
buf_group
} = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = fd;
sqe.ioprio = ioprio;
sqe.__bindgen_anon_2.addr = iovec as _;
sqe.len = len;
sqe.__bindgen_anon_1.off = offset;
sqe.__bindgen_anon_3.rw_flags = rw_flags as _;
sqe.__bindgen_anon_4.buf_group = buf_group;
Entry(sqe)
}
}
opcode! {
#[derive(Debug)]
pub struct Writev {
fd: { RawFd },
iovec: { *const libc::iovec },
len: { u32 },
;;
ioprio: u16 = 0,
offset: u64 = 0,
rw_flags: i32 = 0
}
pub const CODE = bindings::io_uring_op_IORING_OP_WRITEV;
pub fn build(self) -> Entry {
let Writev {
fd,
iovec, len, offset,
ioprio, rw_flags
} = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = fd;
sqe.ioprio = ioprio;
sqe.__bindgen_anon_2.addr = iovec as _;
sqe.len = len;
sqe.__bindgen_anon_1.off = offset;
sqe.__bindgen_anon_3.rw_flags = rw_flags as _;
Entry(sqe)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct FsyncFlags(u32);
impl FsyncFlags {
const DATASYNC: Self = Self(bindings::IORING_FSYNC_DATASYNC);
}
impl FsyncFlags {
pub fn empty() -> Self {
Self(0)
}
fn bits(&self) -> u32 {
self.0
}
}
opcode! {
#[derive(Debug)]
pub struct Fsync {
fd: { RawFd },
;;
flags: FsyncFlags = FsyncFlags::empty()
}
pub const CODE = bindings::io_uring_op_IORING_OP_FSYNC;
pub fn build(self) -> Entry {
let Fsync { fd, flags } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = fd;
sqe.__bindgen_anon_3.fsync_flags = flags.bits();
Entry(sqe)
}
}
opcode! {
#[derive(Debug)]
pub struct ReadFixed {
fd: { RawFd },
buf: { *mut u8 },
len: { u32 },
buf_index: { u16 },
;;
ioprio: u16 = 0,
offset: u64 = 0,
rw_flags: i32 = 0
}
pub const CODE = bindings::io_uring_op_IORING_OP_READ_FIXED;
pub fn build(self) -> Entry {
let ReadFixed {
fd,
buf, len, offset,
buf_index,
ioprio, rw_flags
} = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = fd;
sqe.ioprio = ioprio;
sqe.__bindgen_anon_2.addr = buf as _;
sqe.len = len;
sqe.__bindgen_anon_1.off = offset;
sqe.__bindgen_anon_3.rw_flags = rw_flags as _;
sqe.__bindgen_anon_4.buf_index = buf_index;
Entry(sqe)
}
}
opcode! {
#[derive(Debug)]
pub struct WriteFixed {
fd: { RawFd },
buf: { *const u8 },
len: { u32 },
buf_index: { u16 },
;;
ioprio: u16 = 0,
offset: u64 = 0,
rw_flags: i32 = 0
}
pub const CODE = bindings::io_uring_op_IORING_OP_WRITE_FIXED;
pub fn build(self) -> Entry {
let WriteFixed {
fd,
buf, len, offset,
buf_index,
ioprio, rw_flags
} = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = fd;
sqe.ioprio = ioprio;
sqe.__bindgen_anon_2.addr = buf as _;
sqe.len = len;
sqe.__bindgen_anon_1.off = offset;
sqe.__bindgen_anon_3.rw_flags = rw_flags as _;
sqe.__bindgen_anon_4.buf_index = buf_index;
Entry(sqe)
}
}
opcode! {
#[derive(Debug)]
pub struct PollAdd {
fd: { RawFd },
flags: { u32 },
;;
multi: bool = false
}
pub const CODE = bindings::io_uring_op_IORING_OP_POLL_ADD;
pub fn build(self) -> Entry {
let PollAdd { fd, flags, multi } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = fd;
if multi {
sqe.len = bindings::IORING_POLL_ADD_MULTI;
}
#[cfg(target_endian = "little")] {
sqe.__bindgen_anon_3.poll32_events = flags;
}
#[cfg(target_endian = "big")] {
let x = flags << 16;
let y = flags >> 16;
let flags = x | y;
sqe.__bindgen_anon_3.poll32_events = flags;
}
Entry(sqe)
}
}
opcode! {
#[derive(Debug)]
pub struct PollRemove {
user_data: { u64 }
;;
}
pub const CODE = bindings::io_uring_op_IORING_OP_POLL_REMOVE;
pub fn build(self) -> Entry {
let PollRemove { user_data } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = -1;
sqe.__bindgen_anon_2.addr = user_data;
Entry(sqe)
}
}
opcode! {
#[derive(Debug)]
pub struct SyncFileRange {
fd: { RawFd },
len: { u32 },
;;
offset: u64 = 0,
flags: u32 = 0
}
pub const CODE = bindings::io_uring_op_IORING_OP_SYNC_FILE_RANGE;
pub fn build(self) -> Entry {
let SyncFileRange {
fd,
len, offset,
flags
} = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = fd;
sqe.len = len;
sqe.__bindgen_anon_1.off = offset;
sqe.__bindgen_anon_3.sync_range_flags = flags;
Entry(sqe)
}
}
opcode! {
#[derive(Debug)]
pub struct SendMsg {
fd: { RawFd },
msg: { *const libc::msghdr },
;;
ioprio: u16 = 0,
flags: u32 = 0
}
pub const CODE = bindings::io_uring_op_IORING_OP_SENDMSG;
pub fn build(self) -> Entry {
let SendMsg { fd, msg, ioprio, flags } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = fd;
sqe.ioprio = ioprio;
sqe.__bindgen_anon_2.addr = msg as _;
sqe.len = 1;
sqe.__bindgen_anon_3.msg_flags = flags;
Entry(sqe)
}
}
opcode! {
#[derive(Debug)]
pub struct RecvMsg {
fd: { RawFd },
msg: { *mut libc::msghdr },
;;
ioprio: u16 = 0,
flags: u32 = 0,
buf_group: u16 = 0
}
pub const CODE = bindings::io_uring_op_IORING_OP_RECVMSG;
pub fn build(self) -> Entry {
let RecvMsg { fd, msg, ioprio, flags, buf_group } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = fd;
sqe.ioprio = ioprio;
sqe.__bindgen_anon_2.addr = msg as _;
sqe.len = 1;
sqe.__bindgen_anon_3.msg_flags = flags;
sqe.__bindgen_anon_4.buf_group = buf_group;
Entry(sqe)
}
}
opcode! {
#[derive(Debug)]
pub struct RecvMsgMulti {
fd: { RawFd },
msg: { *const libc::msghdr },
buf_group: { u16 },
;;
ioprio: u16 = 0,
flags: u32 = 0
}
pub const CODE = bindings::io_uring_op_IORING_OP_RECVMSG;
pub fn build(self) -> Entry {
let RecvMsgMulti { fd, msg, buf_group, ioprio, flags } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = fd;
sqe.__bindgen_anon_2.addr = msg as _;
sqe.len = 1;
sqe.__bindgen_anon_3.msg_flags = flags;
sqe.__bindgen_anon_4.buf_group = buf_group;
sqe.flags |= SqeFlags::BUFFER_SELECT.bits();
sqe.ioprio = ioprio | (bindings::IORING_RECV_MULTISHOT as u16);
Entry(sqe)
}
}
#[derive(Debug, Clone, Copy)]
pub struct TimeoutFlags(u32);
impl TimeoutFlags {
const ABS: Self = Self(bindings::IORING_TIMEOUT_ABS);
const BOOTTIME: Self = Self(bindings::IORING_TIMEOUT_BOOTTIME);
const REALTIME: Self = Self(bindings::IORING_TIMEOUT_REALTIME);
const LINK_TIMEOUT_UPDATE: Self = Self(bindings::IORING_LINK_TIMEOUT_UPDATE);
const ETIME_SUCCESS: Self = Self(bindings::IORING_TIMEOUT_ETIME_SUCCESS);
const MULTISHOT: Self = Self(bindings::IORING_TIMEOUT_MULTISHOT);
pub fn empty() -> Self {
Self(0)
}
pub fn bits(self) -> u32 {
self.0
}
}
opcode! {
#[derive(Debug)]
pub struct Timeout {
timespec: { *const bindings::__kernel_timespec },
;;
count: u32 = 0,
flags: TimeoutFlags = TimeoutFlags::empty()
}
pub const CODE = bindings::io_uring_op_IORING_OP_TIMEOUT;
pub fn build(self) -> Entry {
let Timeout { timespec, count, flags } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = -1;
sqe.__bindgen_anon_2.addr = timespec as _;
sqe.len = 1;
sqe.__bindgen_anon_1.off = count as _;
sqe.__bindgen_anon_3.timeout_flags = flags.bits();
Entry(sqe)
}
}
opcode! {
pub struct TimeoutRemove {
user_data: { u64 },
;;
}
pub const CODE = bindings::io_uring_op_IORING_OP_TIMEOUT_REMOVE;
pub fn build(self) -> Entry {
let TimeoutRemove { user_data } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = -1;
sqe.__bindgen_anon_2.addr = user_data;
Entry(sqe)
}
}
opcode! {
pub struct TimeoutUpdate {
user_data: { u64 },
timespec: { *const bindings::__kernel_timespec },
;;
flags: TimeoutFlags = TimeoutFlags::empty()
}
pub const CODE = bindings::io_uring_op_IORING_OP_TIMEOUT_REMOVE;
pub fn build(self) -> Entry {
let TimeoutUpdate { user_data, timespec, flags } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = -1;
sqe.__bindgen_anon_1.off = timespec as _;
sqe.__bindgen_anon_2.addr = user_data;
sqe.__bindgen_anon_3.timeout_flags = flags.bits() | bindings::IORING_TIMEOUT_UPDATE;
Entry(sqe)
}
}
opcode! {
pub struct Accept {
fd: { RawFd },
addr: { *mut libc::sockaddr },
addrlen: { *mut libc::socklen_t },
;;
flags: i32 = 0
}
pub const CODE = bindings::io_uring_op_IORING_OP_ACCEPT;
pub fn build(self) -> Entry {
let Accept { fd, addr, addrlen, flags } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = fd;
sqe.__bindgen_anon_2.addr = addr as _;
sqe.__bindgen_anon_1.addr2 = addrlen as _;
sqe.__bindgen_anon_3.accept_flags = flags as _;
Entry(sqe)
}
}
opcode! {
pub struct AsyncCancel {
user_data: { u64 }
;;
}
pub const CODE = bindings::io_uring_op_IORING_OP_ASYNC_CANCEL;
pub fn build(self) -> Entry {
let AsyncCancel { user_data } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = -1;
sqe.__bindgen_anon_2.addr = user_data;
Entry(sqe)
}
}
opcode! {
pub struct LinkTimeout {
timespec: { *const bindings::__kernel_timespec },
;;
flags: TimeoutFlags = TimeoutFlags::empty()
}
pub const CODE = bindings::io_uring_op_IORING_OP_LINK_TIMEOUT;
pub fn build(self) -> Entry {
let LinkTimeout { timespec, flags } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = -1;
sqe.__bindgen_anon_2.addr = timespec as _;
sqe.len = 1;
sqe.__bindgen_anon_3.timeout_flags = flags.bits();
Entry(sqe)
}
}
opcode! {
pub struct Connect {
fd: { RawFd },
addr: { *const libc::sockaddr },
addrlen: { libc::socklen_t }
;;
}
pub const CODE = bindings::io_uring_op_IORING_OP_CONNECT;
pub fn build(self) -> Entry {
let Connect { fd, addr, addrlen } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = fd;
sqe.__bindgen_anon_2.addr = addr as _;
sqe.__bindgen_anon_1.off = addrlen as _;
Entry(sqe)
}
}
opcode! {
pub struct Fallocate {
fd: { RawFd },
len: { u64 },
;;
offset: u64 = 0,
mode: i32 = 0
}
pub const CODE = bindings::io_uring_op_IORING_OP_FALLOCATE;
pub fn build(self) -> Entry {
let Fallocate { fd, len, offset, mode } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = fd;
sqe.__bindgen_anon_2.addr = len;
sqe.len = mode as _;
sqe.__bindgen_anon_1.off = offset;
Entry(sqe)
}
}
opcode! {
pub struct OpenAt {
dirfd: { RawFd },
pathname: { *const libc::c_char },
;;
flags: i32 = 0,
mode: libc::mode_t = 0
}
pub const CODE = bindings::io_uring_op_IORING_OP_OPENAT;
pub fn build(self) -> Entry {
let OpenAt { dirfd, pathname, flags, mode } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = dirfd;
sqe.__bindgen_anon_2.addr = pathname as _;
sqe.len = mode;
sqe.__bindgen_anon_3.open_flags = flags as _;
Entry(sqe)
}
}
opcode! {
pub struct Close {
fd: { RawFd },
;;
}
pub const CODE = bindings::io_uring_op_IORING_OP_CLOSE;
pub fn build(self) -> Entry {
let Close { fd } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = fd;
Entry(sqe)
}
}
opcode! {
pub struct FilesUpdate {
fds: { *const RawFd },
len: { u32 },
;;
offset: i32 = 0
}
pub const CODE = bindings::io_uring_op_IORING_OP_FILES_UPDATE;
pub fn build(self) -> Entry {
let FilesUpdate { fds, len, offset } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = -1;
sqe.__bindgen_anon_2.addr = fds as _;
sqe.len = len;
sqe.__bindgen_anon_1.off = offset as _;
Entry(sqe)
}
}
opcode! {
pub struct Statx {
dirfd: { RawFd },
pathname: { *const libc::c_char },
statxbuf: { *mut libc::statx },
;;
flags: i32 = 0,
mask: u32 = 0
}
pub const CODE = bindings::io_uring_op_IORING_OP_STATX;
pub fn build(self) -> Entry {
let Statx {
dirfd, pathname, statxbuf,
flags, mask
} = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = dirfd;
sqe.__bindgen_anon_2.addr = pathname as _;
sqe.len = mask;
sqe.__bindgen_anon_1.off = statxbuf as _;
sqe.__bindgen_anon_3.statx_flags = flags as _;
Entry(sqe)
}
}
opcode! {
pub struct Read {
fd: { RawFd },
buf: { *mut u8 },
len: { u32 },
;;
offset: u64 = 0,
ioprio: u16 = 0,
rw_flags: i32 = 0,
buf_group: u16 = 0
}
pub const CODE = bindings::io_uring_op_IORING_OP_READ;
pub fn build(self) -> Entry {
let Read {
fd,
buf, len, offset,
ioprio, rw_flags,
buf_group
} = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = fd;
sqe.ioprio = ioprio;
sqe.__bindgen_anon_2.addr = buf as _;
sqe.len = len;
sqe.__bindgen_anon_1.off = offset;
sqe.__bindgen_anon_3.rw_flags = rw_flags as _;
sqe.__bindgen_anon_4.buf_group = buf_group;
Entry(sqe)
}
}
opcode! {
pub struct Write {
fd: { RawFd },
buf: { *const u8 },
len: { u32 },
;;
offset: u64 = 0,
ioprio: u16 = 0,
rw_flags: i32 = 0
}
pub const CODE = bindings::io_uring_op_IORING_OP_WRITE;
pub fn build(self) -> Entry {
let Write {
fd,
buf, len, offset,
ioprio, rw_flags
} = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = fd;
sqe.ioprio = ioprio;
sqe.__bindgen_anon_2.addr = buf as _;
sqe.len = len;
sqe.__bindgen_anon_1.off = offset;
sqe.__bindgen_anon_3.rw_flags = rw_flags as _;
Entry(sqe)
}
}
opcode! {
pub struct Fadvise {
fd: { RawFd },
len: { libc::off_t },
advice: { i32 },
;;
offset: u64 = 0,
}
pub const CODE = bindings::io_uring_op_IORING_OP_FADVISE;
pub fn build(self) -> Entry {
let Fadvise { fd, len, advice, offset } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = fd;
sqe.len = len as _;
sqe.__bindgen_anon_1.off = offset;
sqe.__bindgen_anon_3.fadvise_advice = advice as _;
Entry(sqe)
}
}
opcode! {
pub struct Madvise {
addr: { *const libc::c_void },
len: { libc::off_t },
advice: { i32 },
;;
}
pub const CODE = bindings::io_uring_op_IORING_OP_MADVISE;
pub fn build(self) -> Entry {
let Madvise { addr, len, advice } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = -1;
sqe.__bindgen_anon_2.addr = addr as _;
sqe.len = len as _;
sqe.__bindgen_anon_3.fadvise_advice = advice as _;
Entry(sqe)
}
}
opcode! {
pub struct Send {
fd: { RawFd },
buf: { *const u8 },
len: { u32 },
;;
flags: i32 = 0,
dest_addr: *const libc::sockaddr = core::ptr::null(),
dest_addr_len: libc::socklen_t = 0,
}
pub const CODE = bindings::io_uring_op_IORING_OP_SEND;
pub fn build(self) -> Entry {
let Send { fd, buf, len, flags, dest_addr, dest_addr_len } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = fd;
sqe.__bindgen_anon_2.addr = buf as _;
sqe.__bindgen_anon_1.addr2 = dest_addr as _;
sqe.__bindgen_anon_5.__bindgen_anon_1.addr_len = dest_addr_len as _;
sqe.len = len;
sqe.__bindgen_anon_3.msg_flags = flags as _;
Entry(sqe)
}
}
opcode! {
pub struct Recv {
fd: { RawFd },
buf: { *mut u8 },
len: { u32 },
;;
flags: i32 = 0,
buf_group: u16 = 0
}
pub const CODE = bindings::io_uring_op_IORING_OP_RECV;
pub fn build(self) -> Entry {
let Recv { fd, buf, len, flags, buf_group } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = fd;
sqe.__bindgen_anon_2.addr = buf as _;
sqe.len = len;
sqe.__bindgen_anon_3.msg_flags = flags as _;
sqe.__bindgen_anon_4.buf_group = buf_group;
Entry(sqe)
}
}
opcode! {
pub struct RecvMulti {
fd: { RawFd },
buf_group: { u16 },
;;
flags: i32 = 0,
}
pub const CODE = bindings::io_uring_op_IORING_OP_RECV;
pub fn build(self) -> Entry {
let RecvMulti { fd, buf_group, flags } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = fd;
sqe.__bindgen_anon_3.msg_flags = flags as _;
sqe.__bindgen_anon_4.buf_group = buf_group;
sqe.flags |= SqeFlags::BUFFER_SELECT.bits();
sqe.ioprio = bindings::IORING_RECV_MULTISHOT as _;
Entry(sqe)
}
}
opcode! {
pub struct EpollCtl {
epfd: { RawFd },
fd: { RawFd },
op: { i32 },
ev: { *const libc::epoll_event },
;;
}
pub const CODE = bindings::io_uring_op_IORING_OP_EPOLL_CTL;
pub fn build(self) -> Entry {
let EpollCtl { epfd, fd, op, ev } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = epfd;
sqe.__bindgen_anon_2.addr = ev as _;
sqe.len = op as _;
sqe.__bindgen_anon_1.off = fd as _;
Entry(sqe)
}
}
opcode! {
pub struct Splice {
fd_in: { RawFd },
off_in: { i64 },
fd_out: { RawFd },
off_out: { i64 },
len: { u32 },
;;
flags: u32 = 0
}
pub const CODE = bindings::io_uring_op_IORING_OP_SPLICE;
pub fn build(self) -> Entry {
let Splice { fd_in, off_in, fd_out, off_out, len, flags } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = fd_out;
sqe.len = len;
sqe.__bindgen_anon_1.off = off_out as _;
sqe.__bindgen_anon_5.splice_fd_in = fd_in;
sqe.__bindgen_anon_2.splice_off_in = off_in as _;
sqe.__bindgen_anon_3.splice_flags = flags;
Entry(sqe)
}
}
opcode! {
pub struct ProvideBuffers {
addr: { *mut u8 },
len: { i32 },
nbufs: { u16 },
bgid: { u16 },
bid: { u16 }
;;
}
pub const CODE = bindings::io_uring_op_IORING_OP_PROVIDE_BUFFERS;
pub fn build(self) -> Entry {
let ProvideBuffers { addr, len, nbufs, bgid, bid } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = nbufs as _;
sqe.__bindgen_anon_2.addr = addr as _;
sqe.len = len as _;
sqe.__bindgen_anon_1.off = bid as _;
sqe.__bindgen_anon_4.buf_group = bgid;
Entry(sqe)
}
}
opcode! {
pub struct RemoveBuffers {
nbufs: { u16 },
bgid: { u16 }
;;
}
pub const CODE = bindings::io_uring_op_IORING_OP_REMOVE_BUFFERS;
pub fn build(self) -> Entry {
let RemoveBuffers { nbufs, bgid } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = nbufs as _;
sqe.__bindgen_anon_4.buf_group = bgid;
Entry(sqe)
}
}
opcode! {
pub struct Tee {
fd_in: { RawFd },
fd_out: { RawFd },
len: { u32 }
;;
flags: u32 = 0
}
pub const CODE = bindings::io_uring_op_IORING_OP_TEE;
pub fn build(self) -> Entry {
let Tee { fd_in, fd_out, len, flags } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = fd_out;
sqe.len = len;
sqe.__bindgen_anon_5.splice_fd_in = fd_in;
sqe.__bindgen_anon_3.splice_flags = flags;
Entry(sqe)
}
}
opcode! {
pub struct Shutdown {
fd: { RawFd },
how: { i32 },
;;
}
pub const CODE = bindings::io_uring_op_IORING_OP_SHUTDOWN;
pub fn build(self) -> Entry {
let Shutdown { fd, how } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = fd;
sqe.len = how as _;
Entry(sqe)
}
}
opcode! {
pub struct RenameAt {
olddirfd: { RawFd },
oldpath: { *const libc::c_char },
newdirfd: { RawFd },
newpath: { *const libc::c_char },
;;
flags: u32 = 0
}
pub const CODE = bindings::io_uring_op_IORING_OP_RENAMEAT;
pub fn build(self) -> Entry {
let RenameAt {
olddirfd, oldpath,
newdirfd, newpath,
flags
} = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = olddirfd;
sqe.__bindgen_anon_2.addr = oldpath as _;
sqe.len = newdirfd as _;
sqe.__bindgen_anon_1.off = newpath as _;
sqe.__bindgen_anon_3.rename_flags = flags;
Entry(sqe)
}
}
opcode! {
pub struct UnlinkAt {
dirfd: { RawFd },
pathname: { *const libc::c_char },
;;
flags: i32 = 0
}
pub const CODE = bindings::io_uring_op_IORING_OP_UNLINKAT;
pub fn build(self) -> Entry {
let UnlinkAt { dirfd, pathname, flags } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = dirfd;
sqe.__bindgen_anon_2.addr = pathname as _;
sqe.__bindgen_anon_3.unlink_flags = flags as _;
Entry(sqe)
}
}
opcode! {
pub struct MkDirAt {
dirfd: { RawFd },
pathname: { *const libc::c_char },
;;
mode: libc::mode_t = 0
}
pub const CODE = bindings::io_uring_op_IORING_OP_MKDIRAT;
pub fn build(self) -> Entry {
let MkDirAt { dirfd, pathname, mode } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = dirfd;
sqe.__bindgen_anon_2.addr = pathname as _;
sqe.len = mode;
Entry(sqe)
}
}
opcode! {
pub struct SymlinkAt {
newdirfd: { RawFd },
target: { *const libc::c_char },
linkpath: { *const libc::c_char },
;;
}
pub const CODE = bindings::io_uring_op_IORING_OP_SYMLINKAT;
pub fn build(self) -> Entry {
let SymlinkAt { newdirfd, target, linkpath } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = newdirfd;
sqe.__bindgen_anon_2.addr = target as _;
sqe.__bindgen_anon_1.addr2 = linkpath as _;
Entry(sqe)
}
}
opcode! {
pub struct LinkAt {
olddirfd: { RawFd },
oldpath: { *const libc::c_char },
newdirfd: { RawFd },
newpath: { *const libc::c_char },
;;
flags: i32 = 0
}
pub const CODE = bindings::io_uring_op_IORING_OP_LINKAT;
pub fn build(self) -> Entry {
let LinkAt { olddirfd, oldpath, newdirfd, newpath, flags } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = olddirfd as _;
sqe.__bindgen_anon_2.addr = oldpath as _;
sqe.len = newdirfd as _;
sqe.__bindgen_anon_1.addr2 = newpath as _;
sqe.__bindgen_anon_3.hardlink_flags = flags as _;
Entry(sqe)
}
}
opcode! {
pub struct GetXattr {
name: { *const libc::c_char },
value: { *mut libc::c_void },
path: { *const libc::c_char },
len: { u32 },
;;
}
pub const CODE = bindings::io_uring_op_IORING_OP_GETXATTR;
pub fn build(self) -> Entry {
let GetXattr { name, value, path, len } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.__bindgen_anon_2.addr = name as _;
sqe.len = len;
sqe.__bindgen_anon_1.off = value as _;
unsafe { sqe.__bindgen_anon_6.__bindgen_anon_1.as_mut().addr3 = path as _ };
sqe.__bindgen_anon_3.xattr_flags = 0;
Entry(sqe)
}
}
opcode! {
pub struct SetXattr {
name: { *const libc::c_char },
value: { *const libc::c_void },
path: { *const libc::c_char },
len: { u32 },
;;
flags: i32 = 0
}
pub const CODE = bindings::io_uring_op_IORING_OP_SETXATTR;
pub fn build(self) -> Entry {
let SetXattr { name, value, path, flags, len } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.__bindgen_anon_2.addr = name as _;
sqe.len = len;
sqe.__bindgen_anon_1.off = value as _;
unsafe { sqe.__bindgen_anon_6.__bindgen_anon_1.as_mut().addr3 = path as _ };
sqe.__bindgen_anon_3.xattr_flags = flags as _;
Entry(sqe)
}
}
opcode! {
pub struct FGetXattr {
fd: { RawFd },
name: { *const libc::c_char },
value: { *mut libc::c_void },
len: { u32 },
;;
}
pub const CODE = bindings::io_uring_op_IORING_OP_FGETXATTR;
pub fn build(self) -> Entry {
let FGetXattr { fd, name, value, len } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = fd;
sqe.__bindgen_anon_2.addr = name as _;
sqe.len = len;
sqe.__bindgen_anon_1.off = value as _;
sqe.__bindgen_anon_3.xattr_flags = 0;
Entry(sqe)
}
}
opcode! {
pub struct FSetXattr {
fd: { RawFd },
name: { *const libc::c_char },
value: { *const libc::c_void },
len: { u32 },
;;
flags: i32 = 0
}
pub const CODE = bindings::io_uring_op_IORING_OP_FSETXATTR;
pub fn build(self) -> Entry {
let FSetXattr { fd, name, value, flags, len } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = fd;
sqe.__bindgen_anon_2.addr = name as _;
sqe.len = len;
sqe.__bindgen_anon_1.off = value as _;
sqe.__bindgen_anon_3.xattr_flags = flags as _;
Entry(sqe)
}
}
opcode! {
pub struct UringCmd16 {
fd: { RawFd },
cmd_op: { u32 },
;;
buf_index: Option<u16> = None,
cmd: [u8; 16] = [0u8; 16]
}
pub const CODE = bindings::io_uring_op_IORING_OP_URING_CMD;
pub fn build(self) -> Entry {
let UringCmd16 { fd, cmd_op, cmd, buf_index } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = fd;
sqe.__bindgen_anon_1.__bindgen_anon_1.cmd_op = cmd_op;
unsafe { *sqe.__bindgen_anon_6.cmd.as_mut().as_mut_ptr().cast::<[u8; 16]>() = cmd };
if let Some(buf_index) = buf_index {
sqe.__bindgen_anon_4.buf_index = buf_index;
unsafe {
sqe.__bindgen_anon_3.uring_cmd_flags |= bindings::IORING_URING_CMD_FIXED;
}
}
Entry(sqe)
}
}
opcode! {
pub struct Socket {
domain: { i32 },
socket_type: { i32 },
protocol: { i32 },
;;
flags: i32 = 0
}
pub const CODE = bindings::io_uring_op_IORING_OP_SOCKET;
pub fn build(self) -> Entry {
let Socket { domain, socket_type, protocol, flags } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = domain as _;
sqe.__bindgen_anon_1.off = socket_type as _;
sqe.len = protocol as _;
sqe.__bindgen_anon_3.rw_flags = flags as _;
Entry(sqe)
}
}
opcode! {
pub struct AcceptMulti {
fd: { RawFd },
;;
allocate_file_index: bool = false,
flags: i32 = 0
}
pub const CODE = bindings::io_uring_op_IORING_OP_ACCEPT;
pub fn build(self) -> Entry {
let AcceptMulti { fd, allocate_file_index, flags } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = fd;
sqe.ioprio = bindings::IORING_ACCEPT_MULTISHOT as u16;
sqe.__bindgen_anon_3.accept_flags = flags as _;
if allocate_file_index {
sqe.__bindgen_anon_5.file_index = bindings::IORING_FILE_INDEX_ALLOC as u32;
}
Entry(sqe)
}
}
opcode! {
pub struct SendZc {
fd: { RawFd },
buf: { *const u8 },
len: { u32 },
;;
buf_index: Option<u16> = None,
dest_addr: *const libc::sockaddr = core::ptr::null(),
dest_addr_len: libc::socklen_t = 0,
flags: i32 = 0,
zc_flags: u16 = 0,
}
pub const CODE = bindings::io_uring_op_IORING_OP_SEND_ZC;
pub fn build(self) -> Entry {
let SendZc { fd, buf, len, buf_index, dest_addr, dest_addr_len, flags, zc_flags } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = fd;
sqe.__bindgen_anon_2.addr = buf as _;
sqe.len = len;
sqe.__bindgen_anon_3.msg_flags = flags as _;
sqe.ioprio = zc_flags;
if let Some(buf_index) = buf_index {
sqe.__bindgen_anon_4.buf_index = buf_index;
sqe.ioprio |= bindings::IORING_RECVSEND_FIXED_BUF as u16;
}
sqe.__bindgen_anon_1.addr2 = dest_addr as _;
sqe.__bindgen_anon_5.__bindgen_anon_1.addr_len = dest_addr_len as _;
Entry(sqe)
}
}
opcode! {
#[derive(Debug)]
pub struct SendMsgZc {
fd: { RawFd },
msg: { *const libc::msghdr },
;;
ioprio: u16 = 0,
flags: u32 = 0
}
pub const CODE = bindings::io_uring_op_IORING_OP_SENDMSG_ZC;
pub fn build(self) -> Entry {
let SendMsgZc { fd, msg, ioprio, flags } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = fd;
sqe.ioprio = ioprio;
sqe.__bindgen_anon_2.addr = msg as _;
sqe.len = 1;
sqe.__bindgen_anon_3.msg_flags = flags;
Entry(sqe)
}
}
opcode! {
pub struct ReadMulti {
fd: { RawFd },
len: { u32 },
buf_group: { u16 },
;;
offset: u64 = 0,
}
pub const CODE = bindings::io_uring_op_IORING_OP_READ_MULTISHOT;
pub fn build(self) -> Entry {
let Self { fd, len, buf_group, offset } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = fd;
sqe.__bindgen_anon_1.off = offset;
sqe.len = len;
sqe.__bindgen_anon_4.buf_group = buf_group;
sqe.flags = SqeFlags::BUFFER_SELECT.bits();
Entry(sqe)
}
}
opcode! {
#[derive(Debug)]
pub struct FutexWait {
futex: { *const u32 },
val: { u64 },
mask: { u64 },
futex_flags: { u32 },
;;
flags: u32 = 0
}
pub const CODE = bindings::io_uring_op_IORING_OP_FUTEX_WAIT;
pub fn build(self) -> Entry {
let FutexWait { futex, val, mask, futex_flags, flags } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = futex_flags as _;
sqe.__bindgen_anon_2.addr = futex as usize as _;
sqe.__bindgen_anon_1.off = val;
unsafe { sqe.__bindgen_anon_6.__bindgen_anon_1.as_mut().addr3 = mask };
sqe.__bindgen_anon_3.futex_flags = flags;
Entry(sqe)
}
}
opcode! {
#[derive(Debug)]
pub struct FutexWake {
futex: { *const u32 },
val: { u64 },
mask: { u64 },
futex_flags: { u32 },
;;
flags: u32 = 0
}
pub const CODE = bindings::io_uring_op_IORING_OP_FUTEX_WAKE;
pub fn build(self) -> Entry {
let FutexWake { futex, val, mask, futex_flags, flags } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = futex_flags as _;
sqe.__bindgen_anon_2.addr = futex as usize as _;
sqe.__bindgen_anon_1.off = val;
unsafe { sqe.__bindgen_anon_6.__bindgen_anon_1.as_mut().addr3 = mask };
sqe.__bindgen_anon_3.futex_flags = flags;
Entry(sqe)
}
}
opcode! {
#[derive(Debug)]
pub struct WaitId {
idtype: { libc::idtype_t },
id: { libc::id_t },
options: { libc::c_int },
;;
infop: *const libc::siginfo_t = std::ptr::null(),
flags: libc::c_uint = 0,
}
pub const CODE = bindings::io_uring_op_IORING_OP_WAITID;
pub fn build(self) -> Entry {
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = self.id as _;
sqe.len = self.idtype as _;
sqe.__bindgen_anon_3.waitid_flags = self.flags;
sqe.__bindgen_anon_5.file_index = self.options as _;
sqe.__bindgen_anon_1.addr2 = self.infop as _;
Entry(sqe)
}
}
opcode! {
#[derive(Debug)]
pub struct Ftruncate {
fd: { RawFd },
len: { u64 },
;;
}
pub const CODE = bindings::io_uring_op_IORING_OP_FTRUNCATE;
pub fn build(self) -> Entry {
let Ftruncate { fd, len } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = fd;
sqe.__bindgen_anon_1.off = len;
Entry(sqe)
}
}
opcode! {
pub struct SendBundle {
fd: { RawFd },
buf_group: { u16 },
;;
flags: i32 = 0,
len: u32 = 0
}
pub const CODE = bindings::io_uring_op_IORING_OP_SEND;
pub fn build(self) -> Entry {
let SendBundle { fd, len, flags, buf_group } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = fd;
sqe.len = len;
sqe.__bindgen_anon_3.msg_flags = flags as _;
sqe.ioprio |= bindings::IORING_RECVSEND_BUNDLE as u16;
sqe.flags |= SqeFlags::BUFFER_SELECT.bits();
sqe.__bindgen_anon_4.buf_group = buf_group;
Entry(sqe)
}
}
opcode! {
pub struct RecvBundle {
fd: { RawFd },
buf_group: { u16 },
;;
flags: i32 = 0
}
pub const CODE = bindings::io_uring_op_IORING_OP_RECV;
pub fn build(self) -> Entry {
let RecvBundle { fd, buf_group, flags } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = fd;
sqe.__bindgen_anon_3.msg_flags = flags as _;
sqe.__bindgen_anon_4.buf_group = buf_group;
sqe.flags |= SqeFlags::BUFFER_SELECT.bits();
sqe.ioprio |= bindings::IORING_RECVSEND_BUNDLE as u16;
Entry(sqe)
}
}
opcode! {
pub struct RecvMultiBundle {
fd: { RawFd },
buf_group: { u16 },
;;
flags: i32 = 0
}
pub const CODE = bindings::io_uring_op_IORING_OP_RECV;
pub fn build(self) -> Entry {
let RecvMultiBundle { fd, buf_group, flags } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = fd;
sqe.__bindgen_anon_3.msg_flags = flags as _;
sqe.__bindgen_anon_4.buf_group = buf_group;
sqe.flags |= SqeFlags::BUFFER_SELECT.bits();
sqe.ioprio = bindings::IORING_RECV_MULTISHOT as _;
sqe.ioprio |= bindings::IORING_RECVSEND_BUNDLE as u16;
Entry(sqe)
}
}
opcode! {
pub struct Bind {
fd: { RawFd },
addr: { *const libc::sockaddr },
addrlen: { libc::socklen_t }
;;
}
pub const CODE = bindings::io_uring_op_IORING_OP_BIND;
pub fn build(self) -> Entry {
let Bind { fd, addr, addrlen } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = fd;
sqe.__bindgen_anon_2.addr = addr as _;
sqe.__bindgen_anon_1.off = addrlen as _;
Entry(sqe)
}
}
opcode! {
pub struct Listen {
fd: { RawFd },
backlog: { i32 },
;;
}
pub const CODE = bindings::io_uring_op_IORING_OP_LISTEN;
pub fn build(self) -> Entry {
let Listen { fd, backlog } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = fd;
sqe.len = backlog as _;
Entry(sqe)
}
}
opcode! {
pub struct RecvZc {
fd: { RawFd },
len: { u32 },
;;
ifq: u32 = 0,
ioprio: u16 = 0,
}
pub const CODE = bindings::io_uring_op_IORING_OP_RECV_ZC;
pub fn build(self) -> Entry {
let Self { fd, len, ifq, ioprio } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = fd;
sqe.len = len;
sqe.ioprio = ioprio | bindings::IORING_RECV_MULTISHOT as u16;
sqe.__bindgen_anon_5.zcrx_ifq_idx = ifq;
Entry(sqe)
}
}
opcode! {
pub struct EpollWait {
fd: { RawFd },
events: { *mut libc::epoll_event },
max_events: { u32 },
;;
flags: u32 = 0,
}
pub const CODE = bindings::io_uring_op_IORING_OP_EPOLL_WAIT;
pub fn build(self) -> Entry {
let Self { fd, events, max_events, flags } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = fd;
sqe.__bindgen_anon_2.addr = events as u64;
sqe.len = max_events;
sqe.__bindgen_anon_3.poll32_events = flags;
Entry(sqe)
}
}
opcode! {
pub struct ReadvFixed {
fd: { RawFd },
iovec: { *const ::libc::iovec },
len: { u32 },
buf_index: { u16 },
;;
ioprio: u16 = 0,
offset: u64 = 0,
rw_flags: i32 = 0,
}
pub const CODE = bindings::io_uring_op_IORING_OP_READV_FIXED;
pub fn build(self) -> Entry {
let Self { fd, iovec, len, buf_index, offset, ioprio, rw_flags } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = fd;
sqe.__bindgen_anon_1.off = offset as _;
sqe.__bindgen_anon_2.addr = iovec as _;
sqe.len = len;
sqe.__bindgen_anon_4.buf_index = buf_index;
sqe.ioprio = ioprio;
sqe.__bindgen_anon_3.rw_flags = rw_flags as _;
Entry(sqe)
}
}
opcode! {
pub struct WritevFixed {
fd: { RawFd },
iovec: { *const ::libc::iovec },
len: { u32 },
buf_index: { u16 },
;;
ioprio: u16 = 0,
offset: u64 = 0,
rw_flags: i32 = 0,
}
pub const CODE = bindings::io_uring_op_IORING_OP_WRITEV_FIXED;
pub fn build(self) -> Entry {
let Self { fd, iovec, len, buf_index, offset, ioprio, rw_flags } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = fd;
sqe.__bindgen_anon_1.off = offset as _;
sqe.__bindgen_anon_2.addr = iovec as _;
sqe.len = len;
sqe.__bindgen_anon_4.buf_index = buf_index;
sqe.ioprio = ioprio;
sqe.__bindgen_anon_3.rw_flags = rw_flags as _;
Entry(sqe)
}
}
opcode! {
pub struct Pipe {
fds: { *mut RawFd },
;;
flags: u32 = 0,
}
pub const CODE = bindings::io_uring_op_IORING_OP_PIPE;
pub fn build(self) -> Entry {
let Self { fds, flags } = self;
let mut sqe = sqe_zeroed();
sqe.opcode = Self::CODE;
sqe.fd = 0;
sqe.__bindgen_anon_2.addr = fds as _;
sqe.__bindgen_anon_3.pipe_flags = flags;
Entry(sqe)
}
}
#[cfg(test)]
mod smoke_tests {
use super::*;
use std::fs::File;
use std::os::fd::AsRawFd;
macro_rules! smoke_test {
($name:ident, $op:expr) => {
pastey::paste! {
#[test]
fn [<smoke_ $name:snake>]() {
let mut ring = crate::LioUring::new(2).unwrap();
let op = $op;
unsafe { ring.push(op.build(), 0x1234) }.unwrap();
}
}
};
}
#[test]
fn smoke_nop() {
let mut ring = crate::LioUring::new(2).unwrap();
let op = Nop::new();
unsafe { ring.push(op.build(), 0x1234) }.unwrap();
ring.submit().unwrap();
let completion = ring.wait().unwrap();
assert_eq!(completion.user_data(), 0x1234);
assert_eq!(completion.result(), 0);
}
#[test]
fn smoke_read() {
let mut ring = crate::LioUring::new(2).unwrap();
let mut buf = vec![0u8; 1024];
let file = File::open("/dev/null").unwrap();
let op =
Read::new(file.as_raw_fd(), buf.as_mut_ptr().cast(), buf.len() as u32);
unsafe { ring.push(op.build(), 0x1234) }.unwrap();
ring.submit().unwrap();
let completion = ring.wait().unwrap();
assert_eq!(completion.user_data(), 0x1234);
assert_eq!(completion.result(), 0); }
#[test]
fn smoke_write() {
let mut ring = crate::LioUring::new(2).unwrap();
let buf = b"Hello, io_uring!";
let file = File::create("/tmp/lio_uring_test_write").unwrap();
let op = Write::new(file.as_raw_fd(), buf.as_ptr(), buf.len() as u32);
unsafe { ring.push(op.build(), 0x1234) }.unwrap();
ring.submit().unwrap();
let completion = ring.wait().unwrap();
assert_eq!(completion.user_data(), 0x1234);
assert_eq!(completion.result(), buf.len() as i32);
}
#[test]
fn smoke_fsync() {
let mut ring = crate::LioUring::new(2).unwrap();
let file = File::create("/tmp/lio_uring_test_fsync").unwrap();
let op = Fsync::new(file.as_raw_fd());
unsafe { ring.push(op.build(), 0x1234) }.unwrap();
ring.submit().unwrap();
let completion = ring.wait().unwrap();
assert_eq!(completion.user_data(), 0x1234);
assert_eq!(completion.result(), 0); }
#[test]
fn smoke_close() {
let mut ring = crate::LioUring::new(2).unwrap();
let file = File::create("/tmp/lio_uring_test_close").unwrap();
let fd = file.as_raw_fd();
core::mem::forget(file); let op = Close::new(fd);
unsafe { ring.push(op.build(), 0x1234) }.unwrap();
ring.submit().unwrap();
let completion = ring.wait().unwrap();
assert_eq!(completion.user_data(), 0x1234);
assert_eq!(completion.result(), 0); }
#[test]
fn smoke_openat() {
let mut ring = crate::LioUring::new(2).unwrap();
let path = b"/tmp/lio_uring_test_open\0";
let op = Openat::new(-100, path.as_ptr().cast()) .flags(libc::O_CREAT | libc::O_WRONLY)
.mode(0o644);
unsafe { ring.push(op.build(), 0x1234) }.unwrap();
ring.submit().unwrap();
let completion = ring.wait().unwrap();
assert_eq!(completion.user_data(), 0x1234);
assert!(completion.result() >= 0); unsafe { libc::close(completion.result()) };
}
#[test]
fn smoke_readv() {
let mut ring = crate::LioUring::new(2).unwrap();
let mut buf1 = vec![0u8; 512];
let mut buf2 = vec![0u8; 512];
let iovecs = [
libc::iovec { iov_base: buf1.as_mut_ptr().cast(), iov_len: buf1.len() },
libc::iovec { iov_base: buf2.as_mut_ptr().cast(), iov_len: buf2.len() },
];
let file = File::open("/dev/zero").unwrap();
let op = Readv::new(file.as_raw_fd(), iovecs.as_ptr().cast(), 2);
unsafe { ring.push(op.build(), 0x1234) }.unwrap();
ring.submit().unwrap();
let completion = ring.wait().unwrap();
assert_eq!(completion.user_data(), 0x1234);
assert_eq!(completion.result(), 1024); }
#[test]
fn smoke_writev() {
let mut ring = crate::LioUring::new(2).unwrap();
let buf1 = b"Hello, ";
let buf2 = b"io_uring!";
let iovecs = [
libc::iovec { iov_base: buf1.as_ptr() as *mut _, iov_len: buf1.len() },
libc::iovec { iov_base: buf2.as_ptr() as *mut _, iov_len: buf2.len() },
];
let file = File::create("/tmp/lio_uring_test_writev").unwrap();
let op = Writev::new(file.as_raw_fd(), iovecs.as_ptr().cast(), 2);
unsafe { ring.push(op.build(), 0x1234) }.unwrap();
ring.submit().unwrap();
let completion = ring.wait().unwrap();
assert_eq!(completion.user_data(), 0x1234);
assert_eq!(completion.result(), 16); }
#[test]
fn smoke_poll_add() {
let mut ring = crate::LioUring::new(2).unwrap();
let file = File::open("/dev/null").unwrap();
let op = PollAdd::new(file.as_raw_fd(), libc::POLLIN as u32);
unsafe { ring.push(op.build(), 0x1234) }.unwrap();
ring.submit().unwrap();
let completion = ring.wait().unwrap();
assert_eq!(completion.user_data(), 0x1234);
assert!(completion.result() >= 0);
}
#[test]
fn smoke_fallocate() {
let mut ring = crate::LioUring::new(2).unwrap();
let file = File::create("/tmp/lio_uring_test_fallocate").unwrap();
let op = Fallocate::new(file.as_raw_fd(), 4096);
unsafe { ring.push(op.build(), 0x1234) }.unwrap();
ring.submit().unwrap();
let completion = ring.wait().unwrap();
assert_eq!(completion.user_data(), 0x1234);
assert_eq!(completion.result(), 0); }
#[test]
fn smoke_fadvise() {
let mut ring = crate::LioUring::new(2).unwrap();
let file = File::open("/dev/null").unwrap();
let op =
Fadvise::new(file.as_raw_fd(), 0, 1024, libc::POSIX_FADV_SEQUENTIAL);
unsafe { ring.push(op.build(), 0x1234) }.unwrap();
ring.submit().unwrap();
let completion = ring.wait().unwrap();
assert_eq!(completion.user_data(), 0x1234);
assert_eq!(completion.result(), 0); }
#[test]
fn smoke_ftruncate() {
use std::io::Write;
let mut ring = crate::LioUring::new(2).unwrap();
let mut file = File::create("/tmp/lio_uring_test_ftruncate").unwrap();
file.write_all(&[0u8; 2048]).unwrap();
file.flush().unwrap();
let op = Ftruncate::new(file.as_raw_fd(), 1024);
unsafe { ring.push(op.build(), 0x1234) }.unwrap();
ring.submit().unwrap();
let completion = ring.wait().unwrap();
assert_eq!(completion.user_data(), 0x1234);
println!("ftruncate result: {}", completion.result());
}
smoke_test!(PollRemove, PollRemove::new(0x5678));
smoke_test!(TimeoutRemove, TimeoutRemove::new(0x5678));
smoke_test!(Cancel, Cancel::new(0x5678));
smoke_test!(Recvmsg, Recvmsg::new(0, core::ptr::null_mut()));
smoke_test!(Sendmsg, Sendmsg::new(1, core::ptr::null()));
smoke_test!(Madvise, Madvise::new(core::ptr::null_mut(), 0, 0));
smoke_test!(Splice, Splice::new(0, 1, 0));
smoke_test!(Tee, Tee::new(0, 1, 0));
smoke_test!(Shutdown, Shutdown::new(0, 0));
smoke_test!(
Renameat,
Renameat::new(-100, core::ptr::null(), -100, core::ptr::null())
);
smoke_test!(Unlinkat, Unlinkat::new(-100, core::ptr::null()));
smoke_test!(Mkdirat, Mkdirat::new(-100, core::ptr::null(), 0));
smoke_test!(
Symlinkat,
Symlinkat::new(core::ptr::null(), -100, core::ptr::null())
);
smoke_test!(
Linkat,
Linkat::new(-100, core::ptr::null(), -100, core::ptr::null())
);
smoke_test!(
Statx,
Statx::new(-100, core::ptr::null(), 0, 0, core::ptr::null_mut())
);
smoke_test!(
Fgetxattr,
Fgetxattr::new(0, core::ptr::null(), core::ptr::null_mut(), 0)
);
smoke_test!(
Fsetxattr,
Fsetxattr::new(0, core::ptr::null(), core::ptr::null(), 0, 0)
);
smoke_test!(Socket, Socket::new(2, 1, 0));
smoke_test!(SocketDirect, SocketDirect::new(2, 1, 0, 0));
smoke_test!(RecvMulti, RecvMulti::new(0, core::ptr::null_mut(), 0));
smoke_test!(
AcceptMulti,
AcceptMulti::new(0, core::ptr::null_mut(), core::ptr::null_mut())
);
smoke_test!(FilesUpdate, FilesUpdate::new(core::ptr::null_mut(), 0, 0));
smoke_test!(Waitid, Waitid::new(0, 0, core::ptr::null_mut(), 0));
smoke_test!(
Getxattr,
Getxattr::new(
core::ptr::null(),
core::ptr::null(),
core::ptr::null_mut(),
0
)
);
smoke_test!(
Setxattr,
Setxattr::new(
core::ptr::null(),
core::ptr::null(),
core::ptr::null(),
0,
0
)
);
smoke_test!(SyncFileRange, SyncFileRange::new(0, 0, 0));
smoke_test!(Epoll, Epoll::new(0, 1, 0, core::ptr::null_mut()));
smoke_test!(
ProvideBuffers,
ProvideBuffers::new(core::ptr::null_mut(), 0, 0, 0, 0)
);
smoke_test!(RemoveBuffers, RemoveBuffers::new(0, 0));
smoke_test!(MsgRing, MsgRing::new(0, 0, 0));
smoke_test!(SendZc, SendZc::new(1, core::ptr::null(), 0));
smoke_test!(SendmsgZc, SendmsgZc::new(1, core::ptr::null()));
smoke_test!(PollUpdate, PollUpdate::new(0, 0, 0));
smoke_test!(LinkTimeout, LinkTimeout::new(core::ptr::null_mut()));
smoke_test!(Bind, Bind::new(0, core::ptr::null(), 0));
smoke_test!(Listen, Listen::new(0, 0));
smoke_test!(FixedFdInstall, FixedFdInstall::new(0));
smoke_test!(SendZcFixed, SendZcFixed::new(1, core::ptr::null(), 0, 0));
smoke_test!(
Openat2,
Openat2::new(-100, core::ptr::null(), core::ptr::null_mut())
);
smoke_test!(MsgRingCqeFlags, MsgRingCqeFlags::new(0, 0, 0, 0));
smoke_test!(CloseFixed, CloseFixed::new(0));
smoke_test!(ReadFixed2, ReadFixed2::new(0, core::ptr::null_mut(), 0, 0, 0));
smoke_test!(WriteFixed2, WriteFixed2::new(1, core::ptr::null(), 0, 0, 0));
smoke_test!(UringCmd, UringCmd::new(0, 0));
smoke_test!(FutexWait, FutexWait::new(core::ptr::null_mut(), 0, 0, 0));
smoke_test!(FutexWake, FutexWake::new(core::ptr::null_mut(), 0, 0, 0));
smoke_test!(FutexWaitv, FutexWaitv::new(core::ptr::null_mut(), 0));
}