Needs Linux 5.6+ (IORING_REGISTER_PROBE): io_uring_get_probe* give None before. An unsupported opcode is not refused at the submit, its completion fails with OSError: EINVAL; probe() gives the whole table as a dict.
io_uring setup parameters (struct io_uring_params): set flags and the sizes before io_uring_queue_init_params / io_uring_setup, read back what the kernel gave after.
Takes no arguments (TypeError for any). features is read only.
Sizes: the ring gets at least entries submission entries, rounded up to a power of two (at most IORING_MAX_ENTRIES, 32768), and twice as many completion entries; IORING_SETUP_CQSIZE uses cq_entries instead (more than entries, rounded up to a power of two, at most 65536). Larger values fail with OSError: EINVAL, or are clamped with IORING_SETUP_CLAMP. The kernel writes the final sizes back.
Completion queue entries (set it with IORING_SETUP_CQSIZE, else the kernel fills it in: twice sq_entries). More room here lets many requests complete before you reap them without an overflow.
Milliseconds the IORING_SETUP_SQPOLL thread polls an empty queue before it sleeps (0: never sleeps, one CPU busy). Asleep, it sets IORING_SQ_NEED_WAKEUP and the next io_uring_submit wakes it with a system call; kept busy, it never sleeps and submits cost no system call.
ring_fd of an existing ring whose async worker pool this ring shares instead of making its own (with IORING_SETUP_ATTACH_WQ; both with IORING_SETUP_SQPOLL: its polling thread too). Not a live ring: OSError: ENXIO.
One ring per thread: a Ring belongs to the thread that initialized it (io_uring_queue_init*), using it (or a CQE / SQE from it) from another thread raises RuntimeError. Threads talk to each other's rings with io_uring_prep_msg_ring. A Cqe or CqeBatch belongs to the thread of its first wait or peek, an Sqe template to the thread of its first prep or put_sqe (another thread: RuntimeError): make one per thread.
user_data can be any 64-bit value, 0 and duplicates included: at the submit the ring keeps it in a table of in-flight requests and gives the kernel the entry's index (an SQE read after the submit shows that index). cqe.user_data gives your value back, until the completion is consumed (io_uring_cqe_seen, io_uring_cq_advance). Cancels, timeout and poll removes / updates and io_uring_register_sync_cancel take your value too: the first in-flight request with it, also with IORING_ASYNC_CANCEL_ALL (each request has its own entry; to cancel a group use IORING_ASYNC_CANCEL_FD | IORING_ASYNC_CANCEL_ALL, or one cancel per request).
A message from io_uring_prep_msg_ring* reports the sender's data as user_data: it is sent with bit 63 set (no request's entry has it), so data must be below 2**63. A message from code that is not Liburing (data without bit 63) would read as one of the ring's requests.
IOSQE_CQE_SKIP_SUCCESS (no completion on success): fine in a link chain (IOSQE_IO_LINK / IOSQE_IO_HARDLINK), whose end's completion releases what the skipped requests hold, but not on the chain's last request (the last SQE of a submit ends a chain): ValueError at the submit, nothing sent. Alone, a request with it may hold nothing (no buffer, path, ...: ValueError) and a failed one reports user_data0.
True: taking an entry from a full submission queue (a prep on Sqe(ring), io_uring_get_sqe, put_sqe) first submits what is queued, as io_uring_submit, and takes the freed slot; except when the last queued request links to the next one (IOSQE_IO_LINK / IOSQE_IO_HARDLINK): a submit would end its chain there, so that call finds the queue full as with False. False (the default): the prep returns False (io_uring_get_sqe: None), you submit and try again.
Probe your system to find out which io_uring operations are available: a dict of every IORING_OP_* name (up to, not including, IORING_OP_LAST) and whether the running kernel supports it.
# or: one operation>>>probe()['IORING_OP_READ']True
Note
Needs Linux 5.6+ (IORING_REGISTER_PROBE), else RuntimeError. Opcodes after the kernel's Probe.last_op are False. Submitting an unsupported opcode is not refused: its completion fails with OSError: EINVAL.
Setup Ring like io_uring_queue_init but with a Param, which lets the caller pass setup flags in and read back what the kernel actually gave.
Note
The kernel fills param in on success: sq_entries, cq_entries (defaults to 2xsq_entries), features and flags (liburing may add its own, e.g. IORING_SETUP_NO_SQARRAY).
entries is rounded up to a power of 2 and must be 1-32768, unless IORING_SETUP_CLAMP is set, which caps it instead of raising OSError.
IORING_SETUP_SQPOLL: the kernel thread sleeps after param.sq_thread_idle ms without work (0: never, io_uring_submit wakes it); IORING_SETUP_SQ_AFF pins it to CPU param.sq_thread_cpu. No privileges needed since Linux 5.13 (OSError: EPERM before).
Setup Ring Submission & Completion Queues. flags are IORING_SETUP_* (default None: none). Returns 0; RuntimeError if ring is already initialized.
entries is the submission queue size (rounded up to a power of 2, max 32768): it caps one submit batch, not the requests in flight. The completion queue gets 2x as many (io_uring_queue_init_params to pick).
Flags
IORING_SETUP_IOPOLL busy-poll completions; O_DIRECT files on a polling capable device
A flag the kernel lacks raises UnsupportedError (on kernels with IORING_REGISTER_QUERY, else OSError: EINVAL). OSError: EPERM: io_uring is disabled (/proc/sys/kernel/io_uring_disabled), or IORING_SETUP_SQPOLL without privileges before Linux 5.13; OSError: ENOMEM: out of locked memory (RLIMIT_MEMLOCK, kernels before 5.12).
IORING_SETUP_IOPOLL allows few opcodes (NOP, READ*/WRITE*, URING_CMD, ...) and needs the device set up for polling (NVMe: poll_queues).
Map the rings of an io_uring file descriptor fd (from io_uring_setup, with the same param) into ring. Returns 0; OSError on failure. io_uring_queue_init* does both steps: this is for a ring set up by hand.
Apply madvise(MADV_DONTFORK) to ring's SQE array, SQ ring and CQ ring, so they are not mapped into a child process after fork().
By default the rings are MAP_SHARED, so a forked child shares them with the parent and both could submit/reap on the same queue. After this call the child simply has no such memory: touching ring in the child (e.g. io_uring_get_sqe) crashes it with SIGSEGV. The parent is not affected and keeps using ring as normal.
Note
ring must be initialized, else raises RuntimeError.
Call it before the fork (os.fork, subprocess, multiprocessing with the fork start method); it does nothing for children already forked. Returns 0; OSError on failure.
Tear down ring: unmap its Submission & Completion Queues and close its fd.
Note
Raises RuntimeError if ring is not initialized or already exited.
Requests still in flight are cancelled and waited for first.
The kernel frees the ring later, from a workqueue: what it locked stays locked a few ms after this returns. Registered buffers count against RLIMIT_MEMLOCK (a buffer inside a huge page pins all of it, 2 MiB), as the rings did before Linux 5.12, so setting up rings with them in a tight loop can hit OSError: ENOMEM.
Resize ring's submission and completion queues to what p says (p.sq_entries, p.cq_entries with IORING_SETUP_CQSIZE). Returns 0; UnsupportedError before Linux 6.13.
Only IORING_SETUP_CQSIZE and IORING_SETUP_CLAMP go in p.flags (the rest is inherited from the setup), other fields of p stay 0. Pending entries are copied over.
OSError: EINVAL when the completion queue is in overflow (io_uring_cq_has_overflow: drain it first); OSError: EEXIST from a thread other than the issuer; OSError: EOVERFLOW for sizes too large without CLAMP. A ring from io_uring_queue_init_mem can not be resized (liburing limitation).
The raw io_uring_enter(2) system call on fd: submit to_submit entries and wait for min_complete completions, flags are IORING_ENTER_*, sig an optional SigsetT. Returns the number of entries consumed (0 when to_submit is 0 or the queue is empty; on an IORING_SETUP_SQPOLL ring just to_submit, the kernel thread does the submitting).
defring_with_completion(ns): ring =make_ring(ns)queue_nops(ring,1)io_uring_submit_and_wait(ring,1)
Note
Other Python threads run while it waits (min_complete > 0).
Only the call's own errors raise here; a failed request raises when its cqe.res is read. InterruptedError (EINTR): a signal while waiting; OSError: EBUSY: overflowed completions could not all be flushed, reap and retry; BlockingIOError (EAGAIN): the kernel is out of resources, reap and retry; OSError: EEXIST: IORING_ENTER_GETEVENTS on an IORING_SETUP_DEFER_TASKRUN ring from another thread; OSError: EBADFD: the ring is still disabled (IORING_SETUP_R_DISABLED).
The raw io_uring_setup(2) system call: makes a ring of entries as p says, p is filled in with what the kernel gave. Returns the file descriptor (use it with io_uring_queue_mmap).
Turn the iowait accounting of a task waiting for completions on (True, what a new ring does) or off (False). Returns 0; UnsupportedError without IORING_FEAT_NO_IOWAIT (Linux 6.15+).
With it on, a wait with requests pending counts as I/O wait (iowait in load and CPU statistics) and keeps the CPU out of deeper sleep states; off is for non-storage work and power. Off, the wait calls pass IORING_ENTER_NO_IOWAIT to io_uring_enter.
Linux 7.2+ (kernel bug): cloning some of src_ring's buffers, when one shares a huge page with a buffer not cloned, miscounts locked memory. Unregistering (or exiting) src_ring first stops counting memory that dst_ring still pins; then dst_ring uncounts it again: the user's count goes below 0, and every small buffer registration fails with OSError: ENOMEM until a reboot. Clone the whole table (io_uring_clone_buffers), or keep each registered buffer off shared huge pages (e.g. its own mmap.mmap with madvise(mmap.MADV_NOHUGEPAGE)).
Linux 6.12+. Returns 0; afterwards both rings have the same registered buffers (as if io_uring_register_buffers had been called on dst_ring with them).
flags defaults to 0 (C's __io_uring_clone_buffers): the rings are found by their real file descriptors, so these must still be open; IORING_REGISTER_SRC_REGISTERED uses src_ring's registered ring fd instead, which only the thread that registered it can.
Both rings must belong to the calling thread.
dst_ring holds src_ring's registered buffers until its own io_uring_unregister_buffers (or its exit): each ring keeps them locked (no resize) while the kernel can use them through it.
Linux 5.10+. Returns 0; OSError: EBADFD when the ring is not disabled. Nothing can be submitted before it; registrations before it are unrestricted, after it they (and submissions) are checked against the restrictions registered (io_uring_register_restrictions).
Needs IORING_FEAT_REG_REG_RING (Linux 6.3+). Returns 1. The ring stays open, reachable only through the registered index: every liburing call keeps working, and nothing (os.close, close_range) can close it by mistake. Only the thread that registered the fd can use the ring then.