Liburing 2026.10.29
static
YoSTEALTH/Liburing

Submission queue

Get a submission entry (SQE / Sqe), set its fields and submit it.

class SQE#

Submission Queue Entry (SQE)

Example

>>> sqe = io_uring_get_sqe(ring)
>>> io_uring_prep_nop(sqe)
True
>>> sqe.user_data = 1
>>> sqe.opcode, sqe.flags
(0, 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)

Note

  • Points into the ring's submission queue (or an Sqe template): RuntimeError once the ring has exited or was initialized again.

property opcode: int#

The IORING_OP_* the entry was prepped with.

property flags: int#

The entry's IOSQE_* flags.

Flags

  • IOSQE_FIXED_FILE fd is an index into the registered files (a direct descriptor). 5.1+
  • IOSQE_IO_DRAIN Starts after every earlier request completed; later ones wait for it. 5.2+
  • IOSQE_IO_LINK The next SQE starts only after this one completes (a chain). 5.3+
  • IOSQE_IO_HARDLINK IOSQE_IO_LINK that keeps the chain going after a failed result. 5.5+
  • IOSQE_ASYNC Hand to a worker thread at once, no non-blocking attempt first. 5.6+
  • IOSQE_BUFFER_SELECT Take a provided buffer of buf_group when the data is ready. 5.7+
  • IOSQE_CQE_SKIP_SUCCESS No completion when the request succeeds. 5.17+ (IORING_FEAT_CQE_SKIP)

Note

  • IOSQE_IO_LINK: a chain runs one request after the other and ends at the first SQE without the flag; a submit ends it too (even if its last SQE has the flag). Any error or unexpected result (a short read) breaks the chain: the requests not started yet complete with OSError: ECANCELED. IOSQE_IO_HARDLINK implies IOSQE_IO_LINK and runs the rest anyway. Chains and single requests outside them run in parallel.
  • IOSQE_BUFFER_SELECT: the completion has IORING_CQE_F_BUFFER set and the buffer id in cqe.flags >> IORING_CQE_BUFFER_SHIFT; OSError: ENOBUFS when the group is empty. A used buffer is gone from the group until it is provided again.
  • IOSQE_CQE_SKIP_SUCCESS: a failed request posts as usual, and without IOSQE_IO_HARDLINK the linked ones after it post nothing. Not to be mixed with IOSQE_IO_DRAIN in one ring (the kernel fails later drains). See Ring for what Liburing refuses at the submit.
  • IOSQE_FIXED_FILE on an operation without fixed file support: OSError: EBADF.

property ioprio: int#

The entry's I/O priority (ioprio_set values, for reads and writes). Network and accept requests reuse the field for their own flags (IORING_RECVSEND_*, IORING_ACCEPT_*), set by their preps.

property fd: int#

The file descriptor the entry works on; with IOSQE_FIXED_FILE in flags the index of a registered file (a direct descriptor) instead.

property len: int#

The entry's len field (e.g. bytes to read, or number of iovec).

property user_data: int#

The user_data of the entry, given back as cqe.user_data in its completion(s): any 64-bit value, 0 and duplicates included (see Ring; after the submit this reads as the ring's index for it).

property personality: int#

The registered personality id (io_uring_register_personality) whose credentials the request runs with (0: none, the submitting thread's; IORING_FEAT_CUR_PERSONALITY).

class Sqe(no=None)#

Subclass of SQE.

IO submission data structure (Submission Queue Entry) (SQE)

Type

no int | Ring | None

Example #1

# `Sqe()` (`None`): one entry, a template `put_sqe` copies into the ring
>>> buf = bytearray(5)
>>> sqe = Sqe()                         # same as `Sqe(1)`
>>> io_uring_prep_read(sqe, fd, buf)
True
>>> sqe.user_data = 1
>>> put_sqe(ring, sqe)                  # *** MUST DO ***
True
>>> io_uring_submit(ring)
1
Setup used to run this example
    'Sqe', 'put_sqe', 'io_uring_prep_open', 'io_uring_prep_open_direct', 'io_uring_prep_read', 'io_uring_prep_write',
    'io_uring_prep_statx', 'Statx', 'io_uring_register_files', 'io_uring_register_files_tags',
)  # fmt: skip
def file_ring(ns):
    '''A ring (2 entries for `put_sqe`, to show a full one), an empty `cqe` and `fd` of `./file.txt`
    (`hi... bye!`).'''
    make_ring(ns, entries=2 if ns['_name'] == 'put_sqe' else 1024)
    ns['cqe'] = Cqe()
    make_file(ns)

Example #2

# `Sqe(2)` (`int`): a block of entries, `sqe[0]` ... `sqe[1]`, put with one `put_sqe`
>>> buf = bytearray(5)
>>> sqe = Sqe(2)
>>> io_uring_prep_write(sqe[0], fd, b'hi...')
True
>>> sqe[0].user_data = 1
>>> io_uring_prep_read(sqe[1], fd, buf)
True
>>> sqe[1].user_data = 2
>>> put_sqe(ring, sqe)                  # *** MUST DO ***
True
>>> io_uring_submit(ring)
2

Example #3

# `Sqe(ring)` (`Ring`): bound to a ring, each prep takes the ring's next free entry
>>> buf = bytearray(5)
>>> sqe = Sqe(ring)
>>> io_uring_prep_read(sqe, fd, buf)    # entry 1
True
>>> sqe.user_data = 1                   # entry 1
>>> io_uring_prep_read(sqe, fd, buf)    # entry 2
True
>>> sqe.user_data = 2                   # entry 2
>>> io_uring_submit(ring)               # both, no `put_sqe`
2

Note

  • This class has two usages: 1. sqe = Sqe(<int>): rather than "get" sqe(s) you are going to "put" pre-made sqe(s) into the ring later (templates). Refer to help(put_sqe) to see more detail. 2. sqe = Sqe(ring): one object for the ring's lifetime, written straight into the ring's submission queue: no io_uring_get_sqe(), no put_sqe(), no object per request.
  • io_uring_get_sqe() returns an SQE (the ring's own entry), not an Sqe: the preps and properties take either.
  • Sqe(no): no must be > 0 (RuntimeError).
  • Sqe(ring): every prep takes the next free entry and returns False if the queue is full (io_uring_submit() and prep again; Ring(auto_submit=True) does that for you); user_data starts at 0. Properties and io_uring_sqe_set_* act on the entry of the last prep (RuntimeError before the first one, or after a full queue). No sqe[i] (which entry is free depends on the kernel) and no put_sqe().

put_sqe(ring: Ring, sqe: Sqe) -> bool#

Put io_uring_sqe into io_uring ring's memory.

Type

ring Ring
sqe Sqe
return bool

Example #1

# single: `Sqe()`
>>> sqe = Sqe()
>>> io_uring_prep_nop(sqe)
True
>>> if put_sqe(ring, sqe):
...     io_uring_submit(ring)  # do stuff
...
1
Setup used to run this example
    'Sqe', 'put_sqe', 'io_uring_prep_open', 'io_uring_prep_open_direct', 'io_uring_prep_read', 'io_uring_prep_write',
    'io_uring_prep_statx', 'Statx', 'io_uring_register_files', 'io_uring_register_files_tags',
)  # fmt: skip
def file_ring(ns):
    '''A ring (2 entries for `put_sqe`, to show a full one), an empty `cqe` and `fd` of `./file.txt`
    (`hi... bye!`).'''
    make_ring(ns, entries=2 if ns['_name'] == 'put_sqe' else 1024)
    ns['cqe'] = Cqe()
    make_file(ns)

Example #2

# multiple: `Sqe(2)`, both entries put with one call
>>> buf = bytearray(5)
>>> sqe = Sqe(2)
>>> io_uring_prep_read(sqe[0], fd, buf)
True
>>> io_uring_prep_write(sqe[1], fd, b'hi...')
True
>>> if put_sqe(ring, sqe):
...     io_uring_submit(ring)  # do stuff
...
2

Example #3

# failed: `ring` was full (2 entries here), submit and try again.
>>> sqe = Sqe(2)
>>> io_uring_prep_nop(sqe[0])
True
>>> io_uring_prep_nop(sqe[1])
True
>>> put_sqe(ring, sqe)
True
>>> put_sqe(ring, sqe)
False
>>> io_uring_submit(ring)
2
>>> put_sqe(ring, sqe)
True

Note

  • Returns False if queue is full. Will need to io_uring_submit() and try again (Ring(auto_submit=True) does that for you, unless the last queued request links on).
  • Returns False if entries < len(sqe)
  • Not for an Sqe(ring) (TypeError): its preps already wrote into the ring.

io_uring_sq_ready(ring: Ring) -> int#

How many entries are queued in the submission queue that the kernel has not consumed yet: not submitted yet, or on an IORING_SETUP_SQPOLL ring not picked up by the kernel thread yet.

Example

>>> io_uring_sq_ready(ring)
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_sq_space_left(ring: Ring) -> int#

How many free entries the submission queue has left.

Example

>>> io_uring_sq_space_left(ring)
1024
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_sqring_wait(ring: Ring) -> int#

Wait for room in the submission queue of an IORING_SETUP_SQPOLL ring (until its kernel thread consumed entries); returns at once when there is room. Returns the call's result, an error is not raised.

Example

>>> io_uring_sqring_wait(ring)
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)

Note

io_uring_get_sqe(ring: Ring) -> SQE | None#

Get the next free entry of the submission queue to prep a request on.

Type

return SQE | None

Example

>>> if sqe := io_uring_get_sqe(ring):
...     io_uring_prep_nop(sqe)
...
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)

Note

  • None when the submission queue is full: io_uring_submit(ring) and try again, or let the ring do it (Ring(auto_submit=True)). Set a request's link flags before taking the next entry: the ring submits only when the last queued request does not link on.
  • Neither this nor the preps set or clear the entry's user_data: set it (io_uring_sqe_set_data64) on every request whose completion you tell apart, or it may carry the value of the slot's previous use.

io_uring_get_sqe128(ring: Ring) -> SQE | None#

An entry that takes two slots (128 bytes) of the submission queue, for io_uring_prep_nop128 and io_uring_prep_uring_cmd128; on a ring set up with IORING_SETUP_SQE128 it is the same as io_uring_get_sqe.

Type

return SQE | None

Example

>>> if sqe := io_uring_get_sqe128(ring):  # `ring` set up with `IORING_SETUP_SQE_MIXED`
...     io_uring_prep_nop128(sqe)
...
True
Setup used to run this example
def ring_sqe_mixed(ns):
    make_ring(ns, flags=IORING_SETUP_SQE_MIXED)

Note

io_uring_submit(ring: Ring) -> int#

Submit the queued entries to the kernel. Returns how many were submitted.

Example

>>> io_uring_submit(ring)  # two entries queued
2
Setup used to run this example
         'io_uring_submit_and_wait_min_timeout', 'io_uring_submit_and_get_events')  # fmt: skip
def queued(ns):
    '''Two NOPs (user_data 1, 2) queued, not submitted; an empty `cqe`.'''
    queue_nops(make_ring(ns), 1, 2)
    ns['cqe'] = Cqe()

Note

  • IORING_SETUP_SQPOLL: it wakes the idle kernel thread instead of entering, and the count can be more than what was really submitted (submit one entry at a time for an exact count).
  • OSError: EBUSY, the completion queue overflowed and could not be flushed (reap, then retry); EAGAIN (BlockingIOError), the kernel is out of resources (same cure). A failed entry is reported in its completion's res, and stops the batch unless the ring has IORING_SETUP_SUBMIT_ALL.

io_uring_submit_and_wait(ring: Ring, wait_nr: int) -> int#

Submit the queued entries and wait for wait_nr completions. Returns how many entries were submitted.

Example

>>> io_uring_submit_and_wait(ring, 2)  # two entries queued
2
Setup used to run this example
         'io_uring_submit_and_wait_min_timeout', 'io_uring_submit_and_get_events')  # fmt: skip
def queued(ns):
    '''Two NOPs (user_data 1, 2) queued, not submitted; an empty `cqe`.'''
    queue_nops(make_ring(ns), 1, 2)
    ns['cqe'] = Cqe()

Note

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

Submit the queued entries and wait for wait_nr completions, or until ts (default None: no limit) runs out. cqe is set to the first one. Returns how many entries were submitted; OSError (errno.ETIME) when ts ran out first.

Example #1

>>> io_uring_submit_and_wait_timeout(ring, cqe, 2)  # two entries queued
2
>>> io_uring_cq_advance(ring, 2)  # done with them
Setup used to run this example
         'io_uring_submit_and_wait_min_timeout', 'io_uring_submit_and_get_events')  # fmt: skip
def queued(ns):
    '''Two NOPs (user_data 1, 2) queued, not submitted; an empty `cqe`.'''
    queue_nops(make_ring(ns), 1, 2)
    ns['cqe'] = Cqe()

Example #2

# or: with a timeout
>>> ts = timespec(0.5)
>>> io_uring_submit_and_wait_timeout(ring, cqe, 2, ts)  # two entries queued
2
>>> io_uring_cq_advance(ring, 2)  # done with them

Note

  • sigmask: signal mask (SigsetT) used only while waiting, signals not in it can interrupt the wait with InterruptedError. None keeps the current mask.
  • Other Python threads run while it sleeps in the kernel. Submit errors as io_uring_submit.
  • Before Linux 5.11 (no IORING_FEAT_EXT_ARG) a ts is an internal IORING_OP_TIMEOUT request that takes a submission queue slot (the call submits first when the queue is full).

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

Submit the queued entries and wait for wait_nr completions like io_uring_submit_and_wait_timeout, with two timeouts: ts is the overall limit and min_wait (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 (see io_uring_wait_cqes_min_timeout). Returns how many entries were submitted; OSError (errno.ETIME) when ts ran out first.

Example

>>> ts = timespec(1)  # overall timeout
>>> io_uring_submit_and_wait_min_timeout(ring, cqe, 2, ts, 1000)  # two entries queued
2
Setup used to run this example
         'io_uring_submit_and_wait_min_timeout', 'io_uring_submit_and_get_events')  # fmt: skip
def queued(ns):
    '''Two NOPs (user_data 1, 2) queued, not submitted; an empty `cqe`.'''
    queue_nops(make_ring(ns), 1, 2)
    ns['cqe'] = Cqe()

Note

  • Needs Linux 6.12+ (IORING_FEAT_MIN_TIMEOUT), else UnsupportedError.
  • Other Python threads run while it sleeps in the kernel. Submit errors as io_uring_submit.
  • 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_submit_and_wait_reg(ring: Ring, cqe: Cqe, wait_nr: int, reg_index: int) -> int#

Submit the queued entries and wait for wait_nr completions, as the registered wait region entry reg_index says (timeouts, see RegWait and io_uring_register_wait_reg; less overhead, nothing is copied). Returns how many entries were submitted; OSError (errno.ETIME) when the region's timeout ran out first.

Example

>>> io_uring_submit_and_wait_reg(ring, cqe, 1, 0)  # one entry queued; wait argument 0 of the region
1
Setup used to run this example
def queued_reg(ns):
    '''A ring with a registered wait region (entry 0: wait up to a second), one NOP queued.'''
    ring = make_ring(ns, entries=8, flags=IORING_SETUP_R_DISABLED)
    mem = mmap.mmap(-1, 4096)
    region = MemRegionReg()
    region.flags = IORING_MEM_REGION_REG_WAIT_ARG
    region.region = mem
    io_uring_register_region(ring, region)
    io_uring_enable_rings(ring)
    wait = RegWait()
    wait.timeout = 1.0
    wait.flags = IORING_REG_WAIT_TS
    mem[0 : RegWait.SIZE] = wait.to_bytes()
    queue_nops(ring, 1)
    ns['cqe'] = Cqe()

Note

  • Linux 6.13+ (IORING_REGISTER_MEM_REGION), else OSError (EINVAL).
  • Fine with nothing queued: a plain wait (returns 0). Other Python threads run while it sleeps.

io_uring_get_events(ring: Ring) -> int#

Flush completions waiting in the kernel (overflowed ones, deferred task work) into the completion queue, without waiting. Returns 0.

Example

>>> io_uring_get_events(ring)
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)

Note

io_uring_submit_and_get_events(ring: Ring) -> int#

io_uring_submit that also flushes waiting completions into the completion queue (io_uring_get_events), in one system call. Returns how many entries were submitted.

Example

>>> io_uring_submit_and_get_events(ring)  # two entries queued
2
Setup used to run this example
         'io_uring_submit_and_wait_min_timeout', 'io_uring_submit_and_get_events')  # fmt: skip
def queued(ns):
    '''Two NOPs (user_data 1, 2) queued, not submitted; an empty `cqe`.'''
    queue_nops(make_ring(ns), 1, 2)
    ns['cqe'] = Cqe()

io_uring_sqe_set_data(sqe: SQE, data: object) -> None#

Attaches the object data to the request sqe prepares: its completion gives it back with io_uring_cqe_get_data (or cqe.data_res(i)), so no table of your own maps user_data back to it. As in C, user_data becomes the object's address (id(data)).

Type

data object

Example

>>> conn = {'fd': 5}
>>> sqe = io_uring_get_sqe(ring)
>>> io_uring_prep_nop(sqe)
True
>>> io_uring_sqe_set_data(sqe, conn)
>>> sqe.user_data == id(conn)
True
>>> io_uring_submit_and_wait(ring, 1)
1
>>> io_uring_wait_cqe(ring, cqe)
0
>>> io_uring_cqe_get_data(cqe[0]) is conn
True
>>> 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_sqe_set_data64(sqe: SQE, data: int) -> None#

Sets the user_data of sqe to the 64-bit data; the completion reports it as cqe.user_data.

Example

>>> io_uring_sqe_set_data64(sqe, 123)
Setup used to run this example
    'io_uring_sqe_set_data64', 'io_uring_sqe_set_flags', 'io_uring_sqe_set_buf_group',
    'io_uring_prep_nop', 'io_uring_prep_provide_buffers', 'Futex', 'timespec',
)  # fmt: skip
def sqe(ns):
    ns['sqe'] = io_uring_get_sqe(make_ring(ns))

Note

  • Set it on every sqe you rely on: one left unset may carry the value of the entry's previous use.

io_uring_sqe_set_flags(sqe: SQE, flags: int) -> None#

Sets the IOSQE_* flags of sqe.

Example

Setup used to run this example
    'io_uring_sqe_set_data64', 'io_uring_sqe_set_flags', 'io_uring_sqe_set_buf_group',
    'io_uring_prep_nop', 'io_uring_prep_provide_buffers', 'Futex', 'timespec',
)  # fmt: skip
def sqe(ns):
    ns['sqe'] = io_uring_get_sqe(make_ring(ns))

Flags

Note

io_uring_sqe_set_buf_group(sqe: SQE, bgid: int) -> None#

Sets the provided buffer group bgid of sqe: the group a request with IOSQE_BUFFER_SELECT takes its buffer from.

Example

>>> io_uring_sqe_set_buf_group(sqe, 123)
Setup used to run this example
    'io_uring_sqe_set_data64', 'io_uring_sqe_set_flags', 'io_uring_sqe_set_buf_group',
    'io_uring_prep_nop', 'io_uring_prep_provide_buffers', 'Futex', 'timespec',
)  # fmt: skip
def sqe(ns):
    ns['sqe'] = io_uring_get_sqe(make_ring(ns))
Generated by tools/setu_docs.py from the docstrings of Liburing 2026.10.29 (CPython 3.14+).