Liburing 2026.10.29
static
YoSTEALTH/Liburing

Completion queue

Wait for, peek at and consume completion entries (CQE / Cqe).

class CQE#

Completion Queue Entry (CQE)

Example

>>> entry = cqe[0]
>>> entry.user_data, entry.res, entry.flags
(1, 0, 0)
Setup used to run this example
    'CQE', 'Cqe.res_at', 'Cqe.user_data_at', 'Cqe.user_data_res', 'io_uring_cqe_seen', 'io_uring_cqe_get_data64',
    'io_uring_cqe_nr',
)  # fmt: skip
def done_seen(ns):
    '''`done`, with `cqe[0]` the first completion (user_data 1).'''
    io_uring_wait_cqe(done(ns), ns['cqe'])

Note

property user_data: int#

The user_data set on the request's sqe (an int): the kernel copies it into every completion of the request; a io_uring_prep_msg_ring* message carries the sender's data here.

property res: int#

The request's result: what the matching system call returns (bytes read or sent, a new file descriptor, 0), or -errno for a failure (io_uring never sets errno); a negative one raises the OSError of that errno. OSError: ECANCELED: the request was cancelled, or an earlier request of its link chain failed.

property flags: int#

The completion's IORING_CQE_F_* flags.

Flags

Note

  • A multishot request (accept, receive, read, poll, timeout) posts one completion per event with IORING_CQE_F_MORE; the one without it is the last (an error, a cancel: res raises OSError: ECANCELED, or no buffer left): re-arm it if wanted. The ring keeps the request's user_data until that last one.
  • A zero-copy send posts its result first (with IORING_CQE_F_MORE), then a notification with IORING_CQE_F_NOTIF and the same user_data once the kernel is done with the buffer.
  • IORING_CQE_F_BUF_MORE only comes from a buffer ring set up with IOU_PBUF_RING_INC: the buffer returns to you when fully used, or on an error.

property big_cqe: bytes | None#

The 16 bytes after a 32-byte completion (a copy): every completion of an IORING_SETUP_CQE32 ring, those with IORING_CQE_F_32 of an IORING_SETUP_CQE_MIXED one. What the request put there (e.g. IORING_OP_URING_CMD); None for a 16-byte completion.

Example

>>> cqe[0].big_cqe  # a NOP on an `IORING_SETUP_CQE32` ring
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
Setup used to run this example
def done_cqe32(ns):
    io_uring_wait_cqe(done(ns, IORING_SETUP_CQE32), ns['cqe'])

class Cqe()#

I/O completion data structure (Completion Queue Entry) (CQE)

Example

>>> cqe = Cqe()
>>> io_uring_wait_cqe(ring, cqe)
0
>>> ready = io_uring_cq_ready(ring)
>>> for i in range(ready):
...     cqe[i].user_data  # do stuff
...
1
2
>>> io_uring_cq_advance(ring, ready)  # free cqe already viewed.
Setup used to run this example
    'Cqe', 'CqeBatch', 'CqeBatchIter', 'CqeIter', 'io_uring_peek_batch_cqe', 'io_uring_wait_cqes',
    'io_uring_wait_cqes_min_timeout', 'io_uring_wait_cqe_timeout', 'io_uring_cqe_iter_init', 'io_uring_cqe_iter_next',
    'io_uring_cq_advance', 'io_uring_cq_ready', 'io_uring_wait_cqe_nr', 'io_uring_peek_cqe', 'io_uring_wait_cqe',
)  # fmt: skip
def done(ns, flags=0):
    '''Two NOPs (user_data 1, 2) completed, still in the completion queue; an empty `cqe`.'''
    ring = make_ring(ns, flags=flags)
    queue_nops(ring, 1, 2)
    io_uring_submit_and_wait(ring, 2)
    ns['cqe'] = Cqe()
    return ring

Note

  • cqe items e.g: cqe[0], cqe[1], ... are not cached (should be called/used only once) and is very dynamic, so make copy if you want to keep data alive for longer use.

method user_data_at(index: int) -> int#

The user_data of cqe[index], without creating an entry object.

Example

>>> for i in range(io_uring_cq_ready(ring)):
...     cqe.user_data_at(i)
...
1
2
Setup used to run this example
    'CQE', 'Cqe.res_at', 'Cqe.user_data_at', 'Cqe.user_data_res', 'io_uring_cqe_seen', 'io_uring_cqe_get_data64',
    'io_uring_cqe_nr',
)  # fmt: skip
def done_seen(ns):
    '''`done`, with `cqe[0]` the first completion (user_data 1).'''
    io_uring_wait_cqe(done(ns), ns['cqe'])

method res_at(index: int) -> int#

The res of cqe[index] (OSError if negative, as CQE.res), without creating an entry object.

Example

>>> cqe.res_at(0)
0
Setup used to run this example
    'CQE', 'Cqe.res_at', 'Cqe.user_data_at', 'Cqe.user_data_res', 'io_uring_cqe_seen', 'io_uring_cqe_get_data64',
    'io_uring_cqe_nr',
)  # fmt: skip
def done_seen(ns):
    '''`done`, with `cqe[0]` the first completion (user_data 1).'''
    io_uring_wait_cqe(done(ns), ns['cqe'])

method user_data_res(index: int) -> tuple[int, int]#

The user_data and res of cqe[index] in one call, without creating an entry object: a server's completion loop reads both. res is returned as is (a negative -errno for a failed request, no OSError), so the user_data of a failed request is not lost to an exception.

Example

>>> cqe.user_data_res(0)
(1, 0)
Setup used to run this example
    'CQE', 'Cqe.res_at', 'Cqe.user_data_at', 'Cqe.user_data_res', 'io_uring_cqe_seen', 'io_uring_cqe_get_data64',
    'io_uring_cqe_nr',
)  # fmt: skip
def done_seen(ns):
    '''`done`, with `cqe[0]` the first completion (user_data 1).'''
    io_uring_wait_cqe(done(ns), ns['cqe'])

method data_res(index: int) -> tuple[Any, int]#

The io_uring_sqe_set_data object (None if none, as io_uring_cqe_get_data) and res of cqe[index] in one call, without creating an entry object; res as is, like user_data_res.

Type

return tuple[Any, int]

Example

>>> conn = {'fd': 5}
>>> sqe = io_uring_get_sqe(ring)
>>> io_uring_prep_nop(sqe)
True
>>> io_uring_sqe_set_data(sqe, conn)
>>> io_uring_submit_and_wait(ring, 1)
1
>>> io_uring_wait_cqe(ring, cqe)
0
>>> cqe.data_res(0)
({'fd': 5}, 0)
>>> io_uring_cqe_seen(ring, cqe[0])
Setup used to run this example
def ring_cqe(ns):
    '''An empty ring and an empty `cqe`: the example makes its own request.'''
    make_ring(ns)
    ns['cqe'] = Cqe()

class CqeBatch(no)#

Caller owned array of CQE pointers, filled by io_uring_peek_batch_cqe. CqeBatch(no) holds up to no of them (no must be > 0, else ValueError); len(batch) is how many the last peek found.

Example

>>> batch = CqeBatch(64)
>>> n = io_uring_peek_batch_cqe(ring, batch)
>>> for cqe in batch:
...     cqe.user_data, cqe.res
...
(1, 0)
(2, 0)
>>> io_uring_cq_advance(ring, n)
Setup used to run this example
    'Cqe', 'CqeBatch', 'CqeBatchIter', 'CqeIter', 'io_uring_peek_batch_cqe', 'io_uring_wait_cqes',
    'io_uring_wait_cqes_min_timeout', 'io_uring_wait_cqe_timeout', 'io_uring_cqe_iter_init', 'io_uring_cqe_iter_next',
    'io_uring_cq_advance', 'io_uring_cq_ready', 'io_uring_wait_cqe_nr', 'io_uring_peek_cqe', 'io_uring_wait_cqe',
)  # fmt: skip
def done(ns, flags=0):
    '''Two NOPs (user_data 1, 2) completed, still in the completion queue; an empty `cqe`.'''
    ring = make_ring(ns, flags=flags)
    queue_nops(ring, 1, 2)
    io_uring_submit_and_wait(ring, 2)
    ns['cqe'] = Cqe()
    return ring

Note

  • Entries point into the ring, only valid until io_uring_cq_advance.
  • Reusable: every peek overwrites previous entries.

class CqeBatchIter#

Iterator over a CqeBatch's entries, from iter(batch) (a for loop): its own position, so loops over one batch don't interfere.

Example

>>> batch = CqeBatch(64)
>>> n = io_uring_peek_batch_cqe(ring, batch)
>>> [(a.user_data, b.user_data) for a in batch for b in batch]
[(1, 1), (1, 2), (2, 1), (2, 2)]
Setup used to run this example
    'Cqe', 'CqeBatch', 'CqeBatchIter', 'CqeIter', 'io_uring_peek_batch_cqe', 'io_uring_wait_cqes',
    'io_uring_wait_cqes_min_timeout', 'io_uring_wait_cqe_timeout', 'io_uring_cqe_iter_init', 'io_uring_cqe_iter_next',
    'io_uring_cq_advance', 'io_uring_cq_ready', 'io_uring_wait_cqe_nr', 'io_uring_peek_cqe', 'io_uring_wait_cqe',
)  # fmt: skip
def done(ns, flags=0):
    '''Two NOPs (user_data 1, 2) completed, still in the completion queue; an empty `cqe`.'''
    ring = make_ring(ns, flags=flags)
    queue_nops(ring, 1, 2)
    io_uring_submit_and_wait(ring, 2)
    ns['cqe'] = Cqe()
    return ring

class CqeIter(ring, cqe, index=None)#

Iterator over the ready completions of ring: each step sets cqe[0] to the next one and gives its index (counted from index, default 0).

Example

>>> for i in CqeIter(ring, cqe):
...     i, cqe[0].user_data  # do stuff
...
(0, 1)
(1, 2)
>>> io_uring_cq_advance(ring, 2)
Setup used to run this example
    'Cqe', 'CqeBatch', 'CqeBatchIter', 'CqeIter', 'io_uring_peek_batch_cqe', 'io_uring_wait_cqes',
    'io_uring_wait_cqes_min_timeout', 'io_uring_wait_cqe_timeout', 'io_uring_cqe_iter_init', 'io_uring_cqe_iter_next',
    'io_uring_cq_advance', 'io_uring_cq_ready', 'io_uring_wait_cqe_nr', 'io_uring_peek_cqe', 'io_uring_wait_cqe',
)  # fmt: skip
def done(ns, flags=0):
    '''Two NOPs (user_data 1, 2) completed, still in the completion queue; an empty `cqe`.'''
    ring = make_ring(ns, flags=flags)
    queue_nops(ring, 1, 2)
    io_uring_submit_and_wait(ring, 2)
    ns['cqe'] = Cqe()
    return ring

Note

io_uring_peek_batch_cqe(ring: Ring, batch: CqeBatch, count: int | None = None) -> int#

Peek up to count (default: all of batch) ready completions without waiting. Returns how many were placed in batch, 0 if none are ready. ValueError if count is larger than batch.

Example

>>> batch = CqeBatch(64)
>>> n = io_uring_peek_batch_cqe(ring, batch)
>>> for cqe in batch:
...     cqe.user_data  # do stuff
...
1
2
>>> io_uring_cq_advance(ring, n)
Setup used to run this example
    'Cqe', 'CqeBatch', 'CqeBatchIter', 'CqeIter', 'io_uring_peek_batch_cqe', 'io_uring_wait_cqes',
    'io_uring_wait_cqes_min_timeout', 'io_uring_wait_cqe_timeout', 'io_uring_cqe_iter_init', 'io_uring_cqe_iter_next',
    'io_uring_cq_advance', 'io_uring_cq_ready', 'io_uring_wait_cqe_nr', 'io_uring_peek_cqe', 'io_uring_wait_cqe',
)  # fmt: skip
def done(ns, flags=0):
    '''Two NOPs (user_data 1, 2) completed, still in the completion queue; an empty `cqe`.'''
    ring = make_ring(ns, flags=flags)
    queue_nops(ring, 1, 2)
    io_uring_submit_and_wait(ring, 2)
    ns['cqe'] = Cqe()
    return ring

Note

io_uring_wait_cqes(ring: Ring, cqe: Cqe, wait_nr: int, ts: Timespec | None = None, sigmask: SigsetT | None = None) -> int#

Wait for at least wait_nr completions, or until ts (default None: no limit) runs out. cqe is set to the first one. Returns 0; OSError (errno.ETIME) when ts ran out first.

Example #1

>>> io_uring_wait_cqes(ring, cqe, 2)
0
Setup used to run this example
    'Cqe', 'CqeBatch', 'CqeBatchIter', 'CqeIter', 'io_uring_peek_batch_cqe', 'io_uring_wait_cqes',
    'io_uring_wait_cqes_min_timeout', 'io_uring_wait_cqe_timeout', 'io_uring_cqe_iter_init', 'io_uring_cqe_iter_next',
    'io_uring_cq_advance', 'io_uring_cq_ready', 'io_uring_wait_cqe_nr', 'io_uring_peek_cqe', 'io_uring_wait_cqe',
)  # fmt: skip
def done(ns, flags=0):
    '''Two NOPs (user_data 1, 2) completed, still in the completion queue; an empty `cqe`.'''
    ring = make_ring(ns, flags=flags)
    queue_nops(ring, 1, 2)
    io_uring_submit_and_wait(ring, 2)
    ns['cqe'] = Cqe()
    return ring

Example #2

# or: with a timeout
>>> ts = timespec(1.5)
>>> io_uring_wait_cqes(ring, cqe, 2, ts)
0

Note

  • Other Python threads run while it sleeps in the kernel.
  • sigmask: signal mask (SigsetT) used only while waiting, signals not in it can interrupt the wait with InterruptedError. None keeps the current mask.
  • No waiting when wait_nr are ready already; 0 says the wait worked, nothing about the res of the completions. The rest after cqe[0] is read with CqeIter or io_uring_peek_batch_cqe.
  • Before Linux 5.11 (no IORING_FEAT_EXT_ARG) a ts is an internal IORING_OP_TIMEOUT request: it takes a submission queue slot and submits what is queued. From 5.11 on nothing is submitted.

io_uring_wait_cqes_min_timeout(ring: Ring, cqe: Cqe, wait_nr: int, ts: Timespec, min_ts_usec: int, sigmask: SigsetT | None = None) -> int#

Wait for wait_nr completions like io_uring_wait_cqes, with two timeouts: ts is the overall limit and min_ts_usec (microseconds) a budget for the whole batch: once it is spent the call returns with whatever has completed, or when nothing has, keeps waiting (up to ts) and returns at the first completion. Returns 0; OSError (errno.ETIME) when ts ran out first.

Example

>>> ts = timespec(1)  # overall timeout
>>> io_uring_wait_cqes_min_timeout(ring, cqe, 2, ts, 1000)
0
Setup used to run this example
    'Cqe', 'CqeBatch', 'CqeBatchIter', 'CqeIter', 'io_uring_peek_batch_cqe', 'io_uring_wait_cqes',
    'io_uring_wait_cqes_min_timeout', 'io_uring_wait_cqe_timeout', 'io_uring_cqe_iter_init', 'io_uring_cqe_iter_next',
    'io_uring_cq_advance', 'io_uring_cq_ready', 'io_uring_wait_cqe_nr', 'io_uring_peek_cqe', 'io_uring_wait_cqe',
)  # fmt: skip
def done(ns, flags=0):
    '''Two NOPs (user_data 1, 2) completed, still in the completion queue; an empty `cqe`.'''
    ring = make_ring(ns, flags=flags)
    queue_nops(ring, 1, 2)
    io_uring_submit_and_wait(ring, 2)
    ns['cqe'] = Cqe()
    return ring

Note

  • Needs Linux 6.12+ (IORING_FEAT_MIN_TIMEOUT), else UnsupportedError.
  • min_ts_usec=0 is a plain io_uring_wait_cqes. The point: batch several completions per wake-up without sleeping the whole ts when few come, and without extra kernel round trips when none come.
  • sigmask: signal mask (SigsetT) used only while waiting, signals not in it can interrupt the wait with InterruptedError. None keeps the current mask.

io_uring_wait_cqe_timeout(ring: Ring, cqe: Cqe, ts: Timespec) -> int#

Wait for one completion, for at most ts. cqe is set to it. Returns 0; OSError (errno.ETIME) when ts ran out first.

Example

>>> ts = timespec(1.5)  # timeout
>>> io_uring_wait_cqe_timeout(ring, cqe, ts)
0
Setup used to run this example
    'Cqe', 'CqeBatch', 'CqeBatchIter', 'CqeIter', 'io_uring_peek_batch_cqe', 'io_uring_wait_cqes',
    'io_uring_wait_cqes_min_timeout', 'io_uring_wait_cqe_timeout', 'io_uring_cqe_iter_init', 'io_uring_cqe_iter_next',
    'io_uring_cq_advance', 'io_uring_cq_ready', 'io_uring_wait_cqe_nr', 'io_uring_peek_cqe', 'io_uring_wait_cqe',
)  # fmt: skip
def done(ns, flags=0):
    '''Two NOPs (user_data 1, 2) completed, still in the completion queue; an empty `cqe`.'''
    ring = make_ring(ns, flags=flags)
    queue_nops(ring, 1, 2)
    io_uring_submit_and_wait(ring, 2)
    ns['cqe'] = Cqe()
    return ring

Note

  • Other Python threads run while it sleeps in the kernel.
  • Before Linux 5.11 (no IORING_FEAT_EXT_ARG) ts is an internal IORING_OP_TIMEOUT request: it takes a submission queue slot and submits what is queued. From 5.11 on nothing is submitted.

io_uring_cqe_iter_init(ring: Ring) -> CqeIter#

Start an iterator over the completions that are ready now.

Type

return CqeIter

Example

>>> cqe_iter = io_uring_cqe_iter_init(ring)
>>> while io_uring_cqe_iter_next(cqe_iter, cqe):
...     cqe[0].user_data
...
1
2
>>> io_uring_cq_advance(ring, 2)
Setup used to run this example
    'Cqe', 'CqeBatch', 'CqeBatchIter', 'CqeIter', 'io_uring_peek_batch_cqe', 'io_uring_wait_cqes',
    'io_uring_wait_cqes_min_timeout', 'io_uring_wait_cqe_timeout', 'io_uring_cqe_iter_init', 'io_uring_cqe_iter_next',
    'io_uring_cq_advance', 'io_uring_cq_ready', 'io_uring_wait_cqe_nr', 'io_uring_peek_cqe', 'io_uring_wait_cqe',
)  # fmt: skip
def done(ns, flags=0):
    '''Two NOPs (user_data 1, 2) completed, still in the completion queue; an empty `cqe`.'''
    ring = make_ring(ns, flags=flags)
    queue_nops(ring, 1, 2)
    io_uring_submit_and_wait(ring, 2)
    ns['cqe'] = Cqe()
    return ring

Note

io_uring_cqe_iter_next(iter: CqeIter, cqe: Cqe) -> bool#

Set cqe[0] to the next ready completion of iter. Returns False when there is none left.

Example

# two requests submitted and completed before
>>> ready = 0
>>> cqe_iter = io_uring_cqe_iter_init(ring)
>>> while io_uring_cqe_iter_next(cqe_iter, cqe):
...     ready += 1
...     entry = cqe[0]  # only index `0` data gets updated!!!
...     entry.user_data, entry.res  # do something with info
...
(1, 0)
(2, 0)
>>> io_uring_cq_advance(ring, ready)  # after the loop (probably faster than `io_uring_cqe_seen` in it)
Setup used to run this example
    'Cqe', 'CqeBatch', 'CqeBatchIter', 'CqeIter', 'io_uring_peek_batch_cqe', 'io_uring_wait_cqes',
    'io_uring_wait_cqes_min_timeout', 'io_uring_wait_cqe_timeout', 'io_uring_cqe_iter_init', 'io_uring_cqe_iter_next',
    'io_uring_cq_advance', 'io_uring_cq_ready', 'io_uring_wait_cqe_nr', 'io_uring_peek_cqe', 'io_uring_wait_cqe',
)  # fmt: skip
def done(ns, flags=0):
    '''Two NOPs (user_data 1, 2) completed, still in the completion queue; an empty `cqe`.'''
    ring = make_ring(ns, flags=flags)
    queue_nops(ring, 1, 2)
    io_uring_submit_and_wait(ring, 2)
    ns['cqe'] = Cqe()
    return ring

Note

  • Only cqe[0] gets updated with new completed entry value.
  • Getting iter is low level and very touchy must be used as shown in example.
  • Consider using CqeIter instead, in for loop.

io_uring_cq_advance(ring: Ring, nr: int) -> None#

Mark nr completions (from the head of the completion queue) as seen, so the kernel can reuse their slots.

Example

>>> io_uring_cq_advance(ring, 2)
Setup used to run this example
    'Cqe', 'CqeBatch', 'CqeBatchIter', 'CqeIter', 'io_uring_peek_batch_cqe', 'io_uring_wait_cqes',
    'io_uring_wait_cqes_min_timeout', 'io_uring_wait_cqe_timeout', 'io_uring_cqe_iter_init', 'io_uring_cqe_iter_next',
    'io_uring_cq_advance', 'io_uring_cq_ready', 'io_uring_wait_cqe_nr', 'io_uring_peek_cqe', 'io_uring_wait_cqe',
)  # fmt: skip
def done(ns, flags=0):
    '''Two NOPs (user_data 1, 2) completed, still in the completion queue; an empty `cqe`.'''
    ring = make_ring(ns, flags=flags)
    queue_nops(ring, 1, 2)
    io_uring_submit_and_wait(ring, 2)
    ns['cqe'] = Cqe()
    return ring

Note

  • Consumes the completions: their user_data (and cqe[i] entries) are not valid after it.
  • Completions not marked seen come back on the next wait or peek. One call for a batch is cheaper than io_uring_cqe_seen per entry: the head is one ordered write the kernel sees.
  • nr counts slots: a 32 byte completion (IORING_SETUP_CQE_MIXED) is io_uring_cqe_nr(cqe) == 2.

io_uring_cqe_seen(ring: Ring, cqe: CQE) -> None#

Mark one completion as seen, so the kernel can reuse its slot.

Example

>>> io_uring_cqe_seen(ring, cqe[0])
Setup used to run this example
    'CQE', 'Cqe.res_at', 'Cqe.user_data_at', 'Cqe.user_data_res', 'io_uring_cqe_seen', 'io_uring_cqe_get_data64',
    'io_uring_cqe_nr',
)  # fmt: skip
def done_seen(ns):
    '''`done`, with `cqe[0]` the first completion (user_data 1).'''
    io_uring_wait_cqe(done(ns), ns['cqe'])

Note

  • Consumes the completion: its user_data is not valid after it.
  • It advances the queue's head, so completions are consumed in queue order whichever cqe is passed; cqe only decides whether 1 or 2 slots (IORING_CQE_F_32) are freed.

io_uring_cqe_get_data(cqe: CQE) -> Any#

The object io_uring_sqe_set_data attached to the request of cqe; None if it has none (C's NULL).

Type

return Any

Example

>>> conn = {'fd': 5}
>>> sqe = io_uring_get_sqe(ring)
>>> io_uring_prep_nop(sqe)
True
>>> io_uring_sqe_set_data(sqe, conn)
>>> io_uring_submit_and_wait(ring, 1)
1
>>> io_uring_wait_cqe(ring, cqe)
0
>>> io_uring_cqe_get_data(cqe[0])
{'fd': 5}
>>> io_uring_cqe_seen(ring, cqe[0])
Setup used to run this example
def ring_cqe(ns):
    '''An empty ring and an empty `cqe`: the example makes its own request.'''
    make_ring(ns)
    ns['cqe'] = Cqe()

Note

io_uring_cqe_get_data64(cqe: CQE) -> int#

The 64-bit user_data of cqe (set with io_uring_sqe_set_data64).

Example

>>> io_uring_cqe_get_data64(cqe[0])
1
Setup used to run this example
    'CQE', 'Cqe.res_at', 'Cqe.user_data_at', 'Cqe.user_data_res', 'io_uring_cqe_seen', 'io_uring_cqe_get_data64',
    'io_uring_cqe_nr',
)  # fmt: skip
def done_seen(ns):
    '''`done`, with `cqe[0]` the first completion (user_data 1).'''
    io_uring_wait_cqe(done(ns), ns['cqe'])

Note

  • Only meaningful when the request's user_data was set: an entry's left-over value comes back otherwise (see io_uring_get_sqe).

io_uring_cqe_nr(cqe: CQE) -> int#

How many completion queue slots cqe takes: 1, or 2 for a big (IORING_CQE_F_32) entry on an IORING_SETUP_CQE_MIXED ring (Linux 6.18+).

Example

>>> io_uring_cq_advance(ring, io_uring_cqe_nr(cqe[0]))
Setup used to run this example
    'CQE', 'Cqe.res_at', 'Cqe.user_data_at', 'Cqe.user_data_res', 'io_uring_cqe_seen', 'io_uring_cqe_get_data64',
    'io_uring_cqe_nr',
)  # fmt: skip
def done_seen(ns):
    '''`done`, with `cqe[0]` the first completion (user_data 1).'''
    io_uring_wait_cqe(done(ns), ns['cqe'])

io_uring_cq_ready(ring: Ring) -> int#

How many completions are ready in the completion queue (posted, not yet marked seen with io_uring_cqe_seen / io_uring_cq_advance).

Example

>>> io_uring_cq_ready(ring)
2
Setup used to run this example
    'Cqe', 'CqeBatch', 'CqeBatchIter', 'CqeIter', 'io_uring_peek_batch_cqe', 'io_uring_wait_cqes',
    'io_uring_wait_cqes_min_timeout', 'io_uring_wait_cqe_timeout', 'io_uring_cqe_iter_init', 'io_uring_cqe_iter_next',
    'io_uring_cq_advance', 'io_uring_cq_ready', 'io_uring_wait_cqe_nr', 'io_uring_peek_cqe', 'io_uring_wait_cqe',
)  # fmt: skip
def done(ns, flags=0):
    '''Two NOPs (user_data 1, 2) completed, still in the completion queue; an empty `cqe`.'''
    ring = make_ring(ns, flags=flags)
    queue_nops(ring, 1, 2)
    io_uring_submit_and_wait(ring, 2)
    ns['cqe'] = Cqe()
    return ring

io_uring_cq_has_overflow(ring: Ring) -> bool#

Whether the kernel holds completions that did not fit the completion queue (IORING_SQ_CQ_OVERFLOW).

Example

>>> io_uring_cq_has_overflow(ring)
False
Setup used to run this example
    'io_uring_get_probe_ring', 'io_uring_ring_dontfork', 'io_uring_queue_exit', 'io_uring_register',
    'io_uring_set_iowait', 'io_uring_sq_ready', 'io_uring_sq_space_left', 'io_uring_sqring_wait', 'io_uring_get_sqe',
    'io_uring_get_events', 'io_uring_close_ring_fd', 'io_uring_register_ring_fd', 'io_uring_unregister_ring_fd',
    'io_uring_register_personality', 'io_uring_unregister_personality', 'io_uring_unregister_files',
    'io_uring_register_eventfd', 'io_uring_unregister_eventfd', 'io_uring_register_buffers', 'io_uring_buf_ring_head',
    'io_uring_register_iowq_aff', 'io_uring_register_iowq_max_workers', 'io_uring_cq_has_overflow',
    'io_uring_cq_eventfd_enabled', 'io_uring_cq_eventfd_toggle', 'BufReg', 'Napi', 'ClockRegister', 'Bpf', 'SQE',
    'SiginfoT', 'io_uring_prep_waitid', 'io_uring_prep_cancel', 'io_uring_prep_cancel64', 'ZcrxIfqReg',
)  # fmt: skip
def ring(ns):
    make_ring(ns)

Note

io_uring_cq_eventfd_enabled(ring: Ring) -> bool#

Whether the registered eventfd is notified of completions (not disabled by io_uring_cq_eventfd_toggle).

Example

>>> io_uring_cq_eventfd_enabled(ring)
True
Setup used to run this example
    'io_uring_get_probe_ring', 'io_uring_ring_dontfork', 'io_uring_queue_exit', 'io_uring_register',
    'io_uring_set_iowait', 'io_uring_sq_ready', 'io_uring_sq_space_left', 'io_uring_sqring_wait', 'io_uring_get_sqe',
    'io_uring_get_events', 'io_uring_close_ring_fd', 'io_uring_register_ring_fd', 'io_uring_unregister_ring_fd',
    'io_uring_register_personality', 'io_uring_unregister_personality', 'io_uring_unregister_files',
    'io_uring_register_eventfd', 'io_uring_unregister_eventfd', 'io_uring_register_buffers', 'io_uring_buf_ring_head',
    'io_uring_register_iowq_aff', 'io_uring_register_iowq_max_workers', 'io_uring_cq_has_overflow',
    'io_uring_cq_eventfd_enabled', 'io_uring_cq_eventfd_toggle', 'BufReg', 'Napi', 'ClockRegister', 'Bpf', 'SQE',
    'SiginfoT', 'io_uring_prep_waitid', 'io_uring_prep_cancel', 'io_uring_prep_cancel64', 'ZcrxIfqReg',
)  # fmt: skip
def ring(ns):
    make_ring(ns)

io_uring_cq_eventfd_toggle(ring: Ring, enabled: bool) -> int#

Turn the registered eventfd's notifications on or off. Returns 0; OSError (EOPNOTSUPP) if the kernel has no flag for it or no eventfd is registered (io_uring_register_eventfd).

Example

>>> io_uring_cq_eventfd_toggle(ring, False)
0
Setup used to run this example
    'io_uring_get_probe_ring', 'io_uring_ring_dontfork', 'io_uring_queue_exit', 'io_uring_register',
    'io_uring_set_iowait', 'io_uring_sq_ready', 'io_uring_sq_space_left', 'io_uring_sqring_wait', 'io_uring_get_sqe',
    'io_uring_get_events', 'io_uring_close_ring_fd', 'io_uring_register_ring_fd', 'io_uring_unregister_ring_fd',
    'io_uring_register_personality', 'io_uring_unregister_personality', 'io_uring_unregister_files',
    'io_uring_register_eventfd', 'io_uring_unregister_eventfd', 'io_uring_register_buffers', 'io_uring_buf_ring_head',
    'io_uring_register_iowq_aff', 'io_uring_register_iowq_max_workers', 'io_uring_cq_has_overflow',
    'io_uring_cq_eventfd_enabled', 'io_uring_cq_eventfd_toggle', 'BufReg', 'Napi', 'ClockRegister', 'Bpf', 'SQE',
    'SiginfoT', 'io_uring_prep_waitid', 'io_uring_prep_cancel', 'io_uring_prep_cancel64', 'ZcrxIfqReg',
)  # fmt: skip
def ring(ns):
    make_ring(ns)

io_uring_wait_cqe_nr(ring: Ring, cqe: Cqe, wait_nr: int) -> int#

Wait until wait_nr completions are ready. cqe is set to the first one. Returns 0.

Example

>>> io_uring_wait_cqe_nr(ring, cqe, 2)
0
Setup used to run this example
    'Cqe', 'CqeBatch', 'CqeBatchIter', 'CqeIter', 'io_uring_peek_batch_cqe', 'io_uring_wait_cqes',
    'io_uring_wait_cqes_min_timeout', 'io_uring_wait_cqe_timeout', 'io_uring_cqe_iter_init', 'io_uring_cqe_iter_next',
    'io_uring_cq_advance', 'io_uring_cq_ready', 'io_uring_wait_cqe_nr', 'io_uring_peek_cqe', 'io_uring_wait_cqe',
)  # fmt: skip
def done(ns, flags=0):
    '''Two NOPs (user_data 1, 2) completed, still in the completion queue; an empty `cqe`.'''
    ring = make_ring(ns, flags=flags)
    queue_nops(ring, 1, 2)
    io_uring_submit_and_wait(ring, 2)
    ns['cqe'] = Cqe()
    return ring

Note

io_uring_peek_cqe(ring: Ring, cqe_ptr: Cqe) -> int#

Set cqe to the first ready completion without waiting. Returns 0; BlockingIOError (EAGAIN) if none is ready.

Example

>>> io_uring_peek_cqe(ring, cqe)
0
Setup used to run this example
    'Cqe', 'CqeBatch', 'CqeBatchIter', 'CqeIter', 'io_uring_peek_batch_cqe', 'io_uring_wait_cqes',
    'io_uring_wait_cqes_min_timeout', 'io_uring_wait_cqe_timeout', 'io_uring_cqe_iter_init', 'io_uring_cqe_iter_next',
    'io_uring_cq_advance', 'io_uring_cq_ready', 'io_uring_wait_cqe_nr', 'io_uring_peek_cqe', 'io_uring_wait_cqe',
)  # fmt: skip
def done(ns, flags=0):
    '''Two NOPs (user_data 1, 2) completed, still in the completion queue; an empty `cqe`.'''
    ring = make_ring(ns, flags=flags)
    queue_nops(ring, 1, 2)
    io_uring_submit_and_wait(ring, 2)
    ns['cqe'] = Cqe()
    return ring

Note

io_uring_wait_cqe(ring: Ring, cqe: Cqe) -> int#

Wait for one completion. cqe is set to it. Returns 0.

Example

>>> io_uring_wait_cqe(ring, cqe)
0
Setup used to run this example
    'Cqe', 'CqeBatch', 'CqeBatchIter', 'CqeIter', 'io_uring_peek_batch_cqe', 'io_uring_wait_cqes',
    'io_uring_wait_cqes_min_timeout', 'io_uring_wait_cqe_timeout', 'io_uring_cqe_iter_init', 'io_uring_cqe_iter_next',
    'io_uring_cq_advance', 'io_uring_cq_ready', 'io_uring_wait_cqe_nr', 'io_uring_peek_cqe', 'io_uring_wait_cqe',
)  # fmt: skip
def done(ns, flags=0):
    '''Two NOPs (user_data 1, 2) completed, still in the completion queue; an empty `cqe`.'''
    ring = make_ring(ns, flags=flags)
    queue_nops(ring, 1, 2)
    io_uring_submit_and_wait(ring, 2)
    ns['cqe'] = Cqe()
    return ring

Note

  • Other Python threads run while it sleeps in the kernel; no waiting when one is ready already. InterruptedError (EINTR) when a signal comes first.
  • 0 says the wait worked, nothing about the request: that is cqe[0].res.
Generated by tools/setu_docs.py from the docstrings of Liburing 2026.10.29 (CPython 3.14+).