Functions
fn accept(self: *IO_Uring, user_data: u64, fd: os.fd_t, addr: ?*os.sockaddr, addrlen: ?*os.socklen_t, flags: u32) !*linux.io_uring_sqe
Queues (but does not submit) an SQE to perform an
accept4(2)
on a socket. Ret…Queues (but does not submit) an SQE to perform an
accept4(2)
on a socket. Returns a pointer to the SQE.fn cancel(self: *IO_Uring, user_data: u64, cancel_user_data: u64, flags: u32) !*linux.io_uring_sqe
Queues (but does not submit) an SQE to remove an existing operation. Returns a …
Queues (but does not submit) an SQE to remove an existing operation. Returns a pointer to the SQE.
The operation is identified by its
user_data
.The completion event result will be
0
if the operation was found and cancelled successfully,-EALREADY
if the operation was found but was already in progress, or-ENOENT
if the operation was not found.fn close(self: *IO_Uring, user_data: u64, fd: os.fd_t) !*linux.io_uring_sqe
Queues (but does not submit) an SQE to perform a
close(2)
. Returns a pointer …Queues (but does not submit) an SQE to perform a
close(2)
. Returns a pointer to the SQE.fn connect(self: *IO_Uring, user_data: u64, fd: os.fd_t, addr: *const os.sockaddr, addrlen: os.socklen_t) !*linux.io_uring_sqe
Queue (but does not submit) an SQE to perform a
connect(2)
on a socket. Retur…Queue (but does not submit) an SQE to perform a
connect(2)
on a socket. Returns a pointer to the SQE.fn copy_cqe(ring: *IO_Uring) !linux.io_uring_cqe
Returns a copy of an I/O completion, waiting for it if necessary, and advancing …
Returns a copy of an I/O completion, waiting for it if necessary, and advancing the CQ ring. A convenience method for
copy_cqes()
for when you don’t need to batch or peek.fn copy_cqes(self: *IO_Uring, cqes: []linux.io_uring_cqe, wait_nr: u32) !u32
Copies as many CQEs as are ready, and that can fit into the destination
cqes
s…Copies as many CQEs as are ready, and that can fit into the destination
cqes
slice. If none are available, enters into the kernel to wait for at mostwait_nr
CQEs. Returns the number of CQEs copied, advancing the CQ ring. Provides all the wait/peek methods found in liburing, but with batching and a single method. The rationale for copying CQEs rather than copying pointers is that pointers are 8 bytes whereas CQEs are not much more at only 16 bytes, and this provides a safer faster interface. Safer, because you no longer need to call cqe_seen(), avoiding idempotency bugs. Faster, because we can now amortize the atomic store release tocq.head
across the batch. See https://github.com/axboe/liburing/issues/103#issuecomment-686665007. Matches the implementation of io_uring_peek_batch_cqe() in liburing, but supports waiting.fn cq_advance(self: *IO_Uring, count: u32) void
For advanced use cases only that implement custom completion queue methods. Mat…
For advanced use cases only that implement custom completion queue methods. Matches the implementation of cq_advance() in liburing.
fn cq_ready(self: *IO_Uring) u32
Returns the number of CQEs in the completion queue, i.e. its length. These are …
Returns the number of CQEs in the completion queue, i.e. its length. These are CQEs that the application is yet to consume. Matches the implementation of io_uring_cq_ready in liburing.
fn cq_ring_needs_flush(self: *IO_Uring) bool
Matches the implementation of cq_ring_needs_flush() in liburing.
fn cqe_seen(self: *IO_Uring, cqe: *linux.io_uring_cqe) void
For advanced use cases only that implement custom completion queue methods. If …
For advanced use cases only that implement custom completion queue methods. If you use copy_cqes() or copy_cqe() you must not call cqe_seen() or cq_advance(). Must be called exactly once after a zero-copy CQE has been processed by your application. Not idempotent, calling more than once will result in other CQEs being lost. Matches the implementation of cqe_seen() in liburing.
fn enter(self: *IO_Uring, to_submit: u32, min_complete: u32, flags: u32) !u32
Tell the kernel we have submitted SQEs and/or want to wait for CQEs. Returns th…
Tell the kernel we have submitted SQEs and/or want to wait for CQEs. Returns the number of SQEs submitted.
fn epoll_ctl(self: *IO_Uring, user_data: u64, epfd: os.fd_t, fd: os.fd_t, op: u32, ev: ?*linux.epoll_event) !*linux.io_uring_sqe
Queues (but does not submit) an SQE to perform a
epoll_ctl(2)
. Returns a poin…Queues (but does not submit) an SQE to perform a
epoll_ctl(2)
. Returns a pointer to the SQE.fn fallocate(self: *IO_Uring, user_data: u64, fd: os.fd_t, mode: i32, offset: u64, len: u64) !*linux.io_uring_sqe
Queues (but does not submit) an SQE to perform an
fallocate(2)
. Returns a poi…Queues (but does not submit) an SQE to perform an
fallocate(2)
. Returns a pointer to the SQE.fn flush_sq(self: *IO_Uring) u32
Sync internal state with kernel ring state on the SQ side. Returns the number o…
Sync internal state with kernel ring state on the SQ side. Returns the number of all pending events in the SQ ring, for the shared ring. This return value includes previously flushed SQEs, as per liburing. The rationale is to suggest that an io_uring_enter() call is needed rather than not. Matches the implementation of __io_uring_flush_sq() in liburing.
fn fsync(self: *IO_Uring, user_data: u64, fd: os.fd_t, flags: u32) !*linux.io_uring_sqe
Queues (but does not submit) an SQE to perform an
fsync(2)
. Returns a pointer…Queues (but does not submit) an SQE to perform an
fsync(2)
. Returns a pointer to the SQE so that you can further modify the SQE for advanced use cases. For example, forfdatasync()
you can setIORING_FSYNC_DATASYNC
in the SQE’srw_flags
. N.B. While SQEs are initiated in the order in which they appear in the submission queue, operations execute in parallel and completions are unordered. Therefore, an application that submits a write followed by an fsync in the submission queue cannot expect the fsync to apply to the write, since the fsync may complete before the write is issued to the disk. You should preferably uselink_with_next_sqe()
on a write’s SQE to link it with an fsync, or else insert a full write barrier usingdrain_previous_sqes()
when queueing an fsync.fn get_sqe(self: *IO_Uring) !*linux.io_uring_sqe
Returns a pointer to a vacant SQE, or an error if the submission queue is full. …
Returns a pointer to a vacant SQE, or an error if the submission queue is full. We follow the implementation (and atomics) of liburing’s
io_uring_get_sqe()
exactly. However, instead of a null we return an error to force safe handling. Any situation where the submission queue is full tends more towards a control flow error, and the null return in liburing is more a C idiom than anything else, for lack of a better alternative. In Zig, we have first-class error handling… so let’s use it. Matches the implementation of io_uring_get_sqe() in liburing.fn init(entries: u13, flags: u32) !IO_Uring
A friendly way to setup an io_uring, with default linux.io_uring_params. `entri…
A friendly way to setup an io_uring, with default linux.io_uring_params.
entries
must be a power of two between 1 and 4096, although the kernel will make the final call on how many entries the submission and completion queues will ultimately have, see https://github.com/torvalds/linux/blob/v5.8/fs/io_uring.c#L8027-L8050. Matches the interface of io_uring_queue_init() in liburing.fn init_params(entries: u13, p: *linux.io_uring_params) !IO_Uring
A powerful way to setup an io_uring, if you want to tweak linux.io_uring_params …
A powerful way to setup an io_uring, if you want to tweak linux.io_uring_params such as submission queue thread cpu affinity or thread idle timeout (the kernel and our default is 1 second).
params
is passed by reference because the kernel needs to modify the parameters. Matches the interface of io_uring_queue_init_params() in liburing.fn link_timeout(self: *IO_Uring, user_data: u64, ts: *const os.linux.kernel_timespec, flags: u32) !*linux.io_uring_sqe
Queues (but does not submit) an SQE to add a link timeout operation. Returns a …
Queues (but does not submit) an SQE to add a link timeout operation. Returns a pointer to the SQE.
You need to set linux.IOSQE_IO_LINK to flags of the target operation and then call this method right after the target operation. See https://lwn.net/Articles/803932/ for detail.
If the dependent request finishes before the linked timeout, the timeout is canceled. If the timeout finishes before the dependent request, the dependent request will be canceled.
The completion event result of the link_timeout will be
-ETIME
if the timeout finishes before the dependent request (in this case, the completion event result of the dependent request will be-ECANCELED
), or-EALREADY
if the dependent request finishes before the linked timeout.fn linkat(self: *IO_Uring, user_data: u64, old_dir_fd: os.fd_t, old_path: [*:0]const u8, new_dir_fd: os.fd_t, new_path: [*:0]const u8, flags: u32) !*linux.io_uring_sqe
Queues (but does not submit) an SQE to perform a
linkat(2)
. Returns a pointer…Queues (but does not submit) an SQE to perform a
linkat(2)
. Returns a pointer to the SQE.fn mkdirat(self: *IO_Uring, user_data: u64, dir_fd: os.fd_t, path: [*:0]const u8, mode: os.mode_t) !*linux.io_uring_sqe
Queues (but does not submit) an SQE to perform a
mkdirat(2)
. Returns a pointe…Queues (but does not submit) an SQE to perform a
mkdirat(2)
. Returns a pointer to the SQE.fn nop(self: *IO_Uring, user_data: u64) !*linux.io_uring_sqe
Queues (but does not submit) an SQE to perform a no-op. Returns a pointer to th…
Queues (but does not submit) an SQE to perform a no-op. Returns a pointer to the SQE so that you can further modify the SQE for advanced use cases. A no-op is more useful than may appear at first glance. For example, you could call
drain_previous_sqes()
on the returned SQE, to use the no-op to know when the ring is idle before acting on a kill signal.fn openat(self: *IO_Uring, user_data: u64, fd: os.fd_t, path: [*:0]const u8, flags: u32, mode: os.mode_t) !*linux.io_uring_sqe
Queues (but does not submit) an SQE to perform an
openat(2)
. Returns a pointe…Queues (but does not submit) an SQE to perform an
openat(2)
. Returns a pointer to the SQE.fn poll_add(self: *IO_Uring, user_data: u64, fd: os.fd_t, poll_mask: u32) !*linux.io_uring_sqe
Queues (but does not submit) an SQE to perform a
poll(2)
. Returns a pointer t…Queues (but does not submit) an SQE to perform a
poll(2)
. Returns a pointer to the SQE.fn poll_remove(self: *IO_Uring, user_data: u64, target_user_data: u64) !*linux.io_uring_sqe
Queues (but does not submit) an SQE to remove an existing poll operation. Retur…
Queues (but does not submit) an SQE to remove an existing poll operation. Returns a pointer to the SQE.
fn poll_update(self: *IO_Uring, user_data: u64, old_user_data: u64, new_user_data: u64, poll_mask: u32, flags: u32) !*linux.io_uring_sqe
Queues (but does not submit) an SQE to update the user data of an existing poll …
Queues (but does not submit) an SQE to update the user data of an existing poll operation. Returns a pointer to the SQE.
fn provide_buffers(self: *IO_Uring, user_data: u64, buffers: [*]u8, buffer_size: usize, buffers_count: usize, group_id: usize, buffer_id: usize) !*linux.io_uring_sqe
Queues (but does not submit) an SQE to provide a group of buffers used for comma…
Queues (but does not submit) an SQE to provide a group of buffers used for commands that read/receive data. Returns a pointer to the SQE.
Provided buffers can be used in
read
,recv
orrecvmsg
commands via .buffer_selection.The kernel expects a contiguous block of memory of size (buffers_count * buffer_size).
fn read(self: *IO_Uring, user_data: u64, fd: os.fd_t, buffer: ReadBuffer, offset: u64) !*linux.io_uring_sqe
Queues (but does not submit) an SQE to perform a
read(2)
orpreadv
depending…Queues (but does not submit) an SQE to perform a
read(2)
orpreadv
depending on the buffer type.- Reading into a
ReadBuffer.buffer
usesread(2)
- Reading into a
ReadBuffer.iovecs
usespreadv(2)
If you want to do apreadv2()
then setrw_flags
on the returned SQE. See https://linux.die.net/man/2/preadv.
Returns a pointer to the SQE.
- Reading into a
fn read_fixed(self: *IO_Uring, user_data: u64, fd: os.fd_t, buffer: *os.iovec, offset: u64, buffer_index: u16) !*linux.io_uring_sqe
Queues (but does not submit) an SQE to perform a IORING_OP_READ_FIXED. The `buf…
Queues (but does not submit) an SQE to perform a IORING_OP_READ_FIXED. The
buffer
provided must be registered with the kernel by callingregister_buffers
first. Thebuffer_index
must be the same as its index in the array provided toregister_buffers
.Returns a pointer to the SQE so that you can further modify the SQE for advanced use cases.
fn recv(self: *IO_Uring, user_data: u64, fd: os.fd_t, buffer: RecvBuffer, flags: u32) !*linux.io_uring_sqe
Queues (but does not submit) an SQE to perform a
recv(2)
. Returns a pointer t…Queues (but does not submit) an SQE to perform a
recv(2)
. Returns a pointer to the SQE.fn recvmsg(self: *IO_Uring, user_data: u64, fd: os.fd_t, msg: *os.msghdr, flags: u32) !*linux.io_uring_sqe
Queues (but does not submit) an SQE to perform a
recvmsg(2)
. Returns a pointe…Queues (but does not submit) an SQE to perform a
recvmsg(2)
. Returns a pointer to the SQE.fn register_buffers(self: *IO_Uring, buffers: []const os.iovec) !void
Registers an array of buffers for use with
read_fixed
andwrite_fixed
.fn register_eventfd(self: *IO_Uring, fd: os.fd_t) !void
Registers the file descriptor for an eventfd that will be notified of completion…
Registers the file descriptor for an eventfd that will be notified of completion events on an io_uring instance. Only a single a eventfd can be registered at any given point in time.
fn register_eventfd_async(self: *IO_Uring, fd: os.fd_t) !void
Registers the file descriptor for an eventfd that will be notified of completion…
Registers the file descriptor for an eventfd that will be notified of completion events on an io_uring instance. Notifications are only posted for events that complete in an async manner. This means that events that complete inline while being submitted do not trigger a notification event. Only a single eventfd can be registered at any given point in time.
fn register_files(self: *IO_Uring, fds: []const os.fd_t) !void
Registers an array of file descriptors. Every time a file descriptor is put in …
Registers an array of file descriptors. Every time a file descriptor is put in an SQE and submitted to the kernel, the kernel must retrieve a reference to the file, and once I/O has completed the file reference must be dropped. The atomic nature of this file reference can be a slowdown for high IOPS workloads. This slowdown can be avoided by pre-registering file descriptors. To refer to a registered file descriptor, IOSQE_FIXED_FILE must be set in the SQE’s flags, and the SQE’s fd must be set to the index of the file descriptor in the registered array. Registering file descriptors will wait for the ring to idle. Files are automatically unregistered by the kernel when the ring is torn down. An application need unregister only if it wants to register a new array of file descriptors.
fn register_files_update(self: *IO_Uring, offset: u32, fds: []const os.fd_t) !void
Updates registered file descriptors.
Updates registered file descriptors.
Updates are applied starting at the provided offset in the original file descriptors slice. There are three kind of updates:
- turning a sparse entry (where the fd is -1) into a real one
- removing an existing entry (set the fd to -1)
- replacing an existing entry with a new fd Adding new file descriptors must be done with
register_files
.
fn remove_buffers(self: *IO_Uring, user_data: u64, buffers_count: usize, group_id: usize) !*linux.io_uring_sqe
Queues (but does not submit) an SQE to remove a group of provided buffers. Retu…
Queues (but does not submit) an SQE to remove a group of provided buffers. Returns a pointer to the SQE.
fn renameat(self: *IO_Uring, user_data: u64, old_dir_fd: os.fd_t, old_path: [*:0]const u8, new_dir_fd: os.fd_t, new_path: [*:0]const u8, flags: u32) !*linux.io_uring_sqe
Queues (but does not submit) an SQE to perform a
renameat2(2)
. Returns a poin…Queues (but does not submit) an SQE to perform a
renameat2(2)
. Returns a pointer to the SQE.fn send(self: *IO_Uring, user_data: u64, fd: os.fd_t, buffer: []const u8, flags: u32) !*linux.io_uring_sqe
Queues (but does not submit) an SQE to perform a
send(2)
. Returns a pointer t…Queues (but does not submit) an SQE to perform a
send(2)
. Returns a pointer to the SQE.fn sendmsg(self: *IO_Uring, user_data: u64, fd: os.fd_t, msg: *const os.msghdr_const, flags: u32) !*linux.io_uring_sqe
Queues (but does not submit) an SQE to perform a
sendmsg(2)
. Returns a pointe…Queues (but does not submit) an SQE to perform a
sendmsg(2)
. Returns a pointer to the SQE.fn shutdown(self: *IO_Uring, user_data: u64, sockfd: os.socket_t, how: u32) !*linux.io_uring_sqe
Queues (but does not submit) an SQE to perform a
shutdown(2)
. Returns a point…Queues (but does not submit) an SQE to perform a
shutdown(2)
. Returns a pointer to the SQE.The operation is identified by its
user_data
.fn sq_ready(self: *IO_Uring) u32
Returns the number of flushed and unflushed SQEs pending in the submission queue…
Returns the number of flushed and unflushed SQEs pending in the submission queue. In other words, this is the number of SQEs in the submission queue, i.e. its length. These are SQEs that the kernel is yet to consume. Matches the implementation of io_uring_sq_ready in liburing.
fn sq_ring_needs_enter(self: *IO_Uring, flags: *u32) bool
Returns true if we are not using an SQ thread (thus nobody submits but us), or …
Returns true if we are not using an SQ thread (thus nobody submits but us), or if IORING_SQ_NEED_WAKEUP is set and the SQ thread must be explicitly awakened. For the latter case, we set the SQ thread wakeup flag. Matches the implementation of sq_ring_needs_enter() in liburing.
fn statx(self: *IO_Uring, user_data: u64, fd: os.fd_t, path: [:0]const u8, flags: u32, mask: u32, buf: *linux.Statx) !*linux.io_uring_sqe
Queues (but does not submit) an SQE to perform an
statx(2)
. Returns a pointer…Queues (but does not submit) an SQE to perform an
statx(2)
. Returns a pointer to the SQE.fn submit(self: *IO_Uring) !u32
Submits the SQEs acquired via get_sqe() to the kernel. You can call this once af…
Submits the SQEs acquired via get_sqe() to the kernel. You can call this once after you have called get_sqe() multiple times to setup multiple I/O requests. Returns the number of SQEs submitted. Matches the implementation of io_uring_submit() in liburing.
fn submit_and_wait(self: *IO_Uring, wait_nr: u32) !u32
Like submit(), but allows waiting for events as well. Returns the number of SQE…
Like submit(), but allows waiting for events as well. Returns the number of SQEs submitted. Matches the implementation of io_uring_submit_and_wait() in liburing.
fn symlinkat(self: *IO_Uring, user_data: u64, target: [*:0]const u8, new_dir_fd: os.fd_t, link_path: [*:0]const u8) !*linux.io_uring_sqe
Queues (but does not submit) an SQE to perform a
symlinkat(2)
. Returns a poin…Queues (but does not submit) an SQE to perform a
symlinkat(2)
. Returns a pointer to the SQE.fn timeout(self: *IO_Uring, user_data: u64, ts: *const os.linux.kernel_timespec, count: u32, flags: u32) !*linux.io_uring_sqe
Queues (but does not submit) an SQE to register a timeout operation. Returns a …
Queues (but does not submit) an SQE to register a timeout operation. Returns a pointer to the SQE.
The timeout will complete when either the timeout expires, or after the specified number of events complete (if
count
is greater than0
).flags
may be0
for a relative timeout, orIORING_TIMEOUT_ABS
for an absolute timeout.The completion event result will be
-ETIME
if the timeout completed through expiration,0
if the timeout completed after the specified number of events, or-ECANCELED
if the timeout was removed before it expired.io_uring timeouts use the
CLOCK.MONOTONIC
clock source.fn timeout_remove(self: *IO_Uring, user_data: u64, timeout_user_data: u64, flags: u32) !*linux.io_uring_sqe
Queues (but does not submit) an SQE to remove an existing timeout operation. Re…
Queues (but does not submit) an SQE to remove an existing timeout operation. Returns a pointer to the SQE.
The timeout is identified by its
user_data
.The completion event result will be
0
if the timeout was found and cancelled successfully,-EBUSY
if the timeout was found but expiration was already in progress, or-ENOENT
if the timeout was not found.fn unlinkat(self: *IO_Uring, user_data: u64, dir_fd: os.fd_t, path: [*:0]const u8, flags: u32) !*linux.io_uring_sqe
Queues (but does not submit) an SQE to perform a
unlinkat(2)
. Returns a point…Queues (but does not submit) an SQE to perform a
unlinkat(2)
. Returns a pointer to the SQE.fn unregister_files(self: *IO_Uring) !void
Unregisters all registered file descriptors previously associated with the ring.
fn write(self: *IO_Uring, user_data: u64, fd: os.fd_t, buffer: []const u8, offset: u64) !*linux.io_uring_sqe
Queues (but does not submit) an SQE to perform a
write(2)
. Returns a pointer …Queues (but does not submit) an SQE to perform a
write(2)
. Returns a pointer to the SQE.fn write_fixed(self: *IO_Uring, user_data: u64, fd: os.fd_t, buffer: *os.iovec, offset: u64, buffer_index: u16) !*linux.io_uring_sqe
Queues (but does not submit) an SQE to perform a IORING_OP_WRITE_FIXED. The `bu…
Queues (but does not submit) an SQE to perform a IORING_OP_WRITE_FIXED. The
buffer
provided must be registered with the kernel by callingregister_buffers
first. Thebuffer_index
must be the same as its index in the array provided toregister_buffers
.Returns a pointer to the SQE so that you can further modify the SQE for advanced use cases.
fn writev(self: *IO_Uring, user_data: u64, fd: os.fd_t, iovecs: []const os.iovec_const, offset: u64) !*linux.io_uring_sqe
Queues (but does not submit) an SQE to perform a
pwritev()
. Returns a pointer…Queues (but does not submit) an SQE to perform a
pwritev()
. Returns a pointer to the SQE so that you can further modify the SQE for advanced use cases. For example, if you want to do apwritev2()
then setrw_flags
on the returned SQE. See https://linux.die.net/man/2/pwritev.