io_uring
nimony/lib/std/posix/io_uring.nim
type KernelRwfT = int32_kernelrwf_t (a plain int in the kernel uapi)
type SqeFlag = enum SQE_FIXED_FILE = (0, "SQE_FIXED_FILE") SQE_IO_DRAIN = (1, "SQE_IO_DRAIN") SQE_IO_LINK = (2, "SQE_IO_LINK") SQE_IO_HARDLINK = (3, "SQE_IO_HARDLINK") SQE_ASYNC = (4, "SQE_ASYNC") SQE_BUFFER_SELECT = (5, "SQE_BUFFER_SELECT") SQE_CQE_SKIP_SUCCESS = (6, "SQE_CQE_SKIP_SUCCESS")
func dollar`.SqeFlag(e: SqeFlag): stringtype SqeFlags = set[SqeFlag]type FsyncFlag = enum FSYNC_DATASYNC = (0, "FSYNC_DATASYNC")
func dollar`.FsyncFlag(e: FsyncFlag): stringtype FsyncFlags = set[FsyncFlag]type TimeoutFlag = enum TIMEOUT_ABS = (0, "TIMEOUT_ABS") TIMEOUT_UPDATE = (1, "TIMEOUT_UPDATE") TIMEOUT_BOOTTIME = (2, "TIMEOUT_BOOTTIME") TIMEOUT_REALTIME = (3, "TIMEOUT_REALTIME") LINK_TIMEOUT_UPDATE = (4, "LINK_TIMEOUT_UPDATE") TIMEOUT_ETIME_SUCCESS = (5, "TIMEOUT_ETIME_SUCCESS")
func dollar`.TimeoutFlag(e: TimeoutFlag): stringtype TimeoutFlags = set[TimeoutFlag]type PollFlag = enum POLL_ADD_MULTI = (0, "POLL_ADD_MULTI") POLL_UPDATE_EVENTS = (1, "POLL_UPDATE_EVENTS") POLL_UPDATE_USER_DATA = (2, "POLL_UPDATE_USER_DATA") POLL_ADD_LEVEL = (3, "POLL_ADD_LEVEL")
func dollar`.PollFlag(e: PollFlag): stringtype PollFlags = set[PollFlag]type PollEvent = enum POLL_IN = (0, "POLL_IN") POLL_PRI = (1, "POLL_PRI") POLL_OUT = (2, "POLL_OUT") POLL_ERR = (3, "POLL_ERR") POLL_HUP = (4, "POLL_HUP") POLL_NVAL = (5, "POLL_NVAL") POLL_RDNORM = (6, "POLL_RDNORM") POLL_RDBAND = (7, "POLL_RDBAND") POLL_WRNORM = (8, "POLL_WRNORM") POLL_WRBAND = (9, "POLL_WRBAND") POLL_MSG = (10, "POLL_MSG") POLL_RESERVED11 = (11, "POLL_RESERVED11") POLL_REMOVE = (12, "POLL_REMOVE") POLL_RDHUP = (13, "POLL_RDHUP")
func dollar`.PollEvent(e: PollEvent): stringtype PollEvents = set[PollEvent]type MsgFlag = enum MSG_OOB = (0, "MSG_OOB") MSG_PEEK = (1, "MSG_PEEK") MSG_DONTROUTE = (2, "MSG_DONTROUTE") MSG_CTRUNC = (3, "MSG_CTRUNC") MSG_PROXY = (4, "MSG_PROXY") MSG_TRUNC = (5, "MSG_TRUNC") MSG_DONTWAIT = (6, "MSG_DONTWAIT") MSG_EOR = (7, "MSG_EOR") MSG_WAITALL = (8, "MSG_WAITALL") MSG_FIN = (9, "MSG_FIN") MSG_SYN = (10, "MSG_SYN") MSG_CONFIRM = (11, "MSG_CONFIRM") MSG_RST = (12, "MSG_RST") MSG_ERRQUEUE = (13, "MSG_ERRQUEUE") MSG_NOSIGNAL = (14, "MSG_NOSIGNAL") MSG_MORE = (15, "MSG_MORE") MSG_WAITFORONE = (16, "MSG_WAITFORONE")
func dollar`.MsgFlag(e: MsgFlag): stringtype MsgFlags = set[MsgFlag]type SyncFileRangeFlag = enum SYNC_FILE_RANGE_WAIT_BEFORE = (0, "SYNC_FILE_RANGE_WAIT_BEFORE") SYNC_FILE_RANGE_WRITE = (1, "SYNC_FILE_RANGE_WRITE") SYNC_FILE_RANGE_WAIT_AFTER = (2, "SYNC_FILE_RANGE_WAIT_AFTER")
func dollar`.SyncFileRangeFlag(e: SyncFileRangeFlag): stringtype SyncFileRangeFlags = set[SyncFileRangeFlag]type SpliceFlag = enum SPLICE_F_MOVE = (0, "SPLICE_F_MOVE") SPLICE_F_NONBLOCK = (1, "SPLICE_F_NONBLOCK") SPLICE_F_MORE = (2, "SPLICE_F_MORE") SPLICE_F_GIFT = (3, "SPLICE_F_GIFT")
func dollar`.SpliceFlag(e: SpliceFlag): stringtype SpliceFlags = set[SpliceFlag]type RenameFlag = enum RENAME_NOREPLACE = (0, "RENAME_NOREPLACE") RENAME_EXCHANGE = (1, "RENAME_EXCHANGE") RENAME_WHITEOUT = (2, "RENAME_WHITEOUT")
func dollar`.RenameFlag(e: RenameFlag): stringtype RenameFlags = set[RenameFlag]type StatxField = enum STATX_TYPE = (0, "STATX_TYPE") STATX_MODE = (1, "STATX_MODE") STATX_NLINK = (2, "STATX_NLINK") STATX_UID = (3, "STATX_UID") STATX_GID = (4, "STATX_GID") STATX_ATIME = (5, "STATX_ATIME") STATX_MTIME = (6, "STATX_MTIME") STATX_CTIME = (7, "STATX_CTIME") STATX_INO = (8, "STATX_INO") STATX_SIZE = (9, "STATX_SIZE") STATX_BLOCKS = (10, "STATX_BLOCKS") STATX_BTIME = (11, "STATX_BTIME") STATX_MNT_ID = (12, "STATX_MNT_ID") STATX_DIOALIGN = (13, "STATX_DIOALIGN")
func dollar`.StatxField(e: StatxField): stringtype StatxFields = set[StatxField]type XattrFlag = enum XATTR_CREATE = (0, "XATTR_CREATE") XATTR_REPLACE = (1, "XATTR_REPLACE")
func dollar`.XattrFlag(e: XattrFlag): stringtype XattrFlags = set[XattrFlag]type ShutdownHow = enum SHUT_RD = (0, "SHUT_RD") SHUT_WR = (1, "SHUT_WR") SHUT_RDWR = (2, "SHUT_RDWR")
func dollar`.ShutdownHow(e: ShutdownHow): stringtype AsyncCancelFlag = enum ASYNC_CANCEL_ALL = (0, "ASYNC_CANCEL_ALL") ASYNC_CANCEL_FD = (1, "ASYNC_CANCEL_FD") ASYNC_CANCEL_ANY = (2, "ASYNC_CANCEL_ANY") ASYNC_CANCEL_FD_FIXED = (3, "ASYNC_CANCEL_FD_FIXED")
func dollar`.AsyncCancelFlag(e: AsyncCancelFlag): stringtype AsyncCancelFlags = set[AsyncCancelFlag]type IoprioFlag = enum RECVSEND_POLL_FIRST = (0, "RECVSEND_POLL_FIRST") RECV_MULTISHOT = (1, "RECV_MULTISHOT") RECVSEND_FIXED_BUF = (2, "RECVSEND_FIXED_BUF") SEND_ZC_REPORT_USAGE = (3, "SEND_ZC_REPORT_USAGE")
func dollar`.IoprioFlag(e: IoprioFlag): stringtype IoprioFlags = set[IoprioFlag]type MsgRingOp = enum MSG_DATA = (0, "MSG_DATA") MSG_SEND_FD = (1, "MSG_SEND_FD")
func dollar`.MsgRingOp(e: MsgRingOp): stringtype MsgRingOpFlag = enum MSG_RING_CQE_SKIP = (0, "MSG_RING_CQE_SKIP") MSG_RING_FLAGS_PASS = (1, "MSG_RING_FLAGS_PASS")
func dollar`.MsgRingOpFlag(e: MsgRingOpFlag): stringtype MsgRingOpFlags = set[MsgRingOpFlag]type InnerSqeFlags = object rwFlags: int32 fsyncFlags: set[FsyncFlag] poll32Events: set[PollEvent] syncRangeFlags: set[SyncFileRangeFlag] msgFlags: set[MsgFlag] timeoutFlags: set[TimeoutFlag] acceptFlags: uint32 cancelFlags: set[AsyncCancelFlag] openFlags: uint32 statxFlags: uint32 fadviseAdvice: uint32 spliceFlags: uint32 renameFlags: set[RenameFlag] unlinkFlags: uint32 hardlinkFlags: uint32 xattrFlags: set[XattrFlag] msgRingFlags: set[MsgRingOpFlag] uringCmdFlags: uint32
type InnerSqeBuf = object bufIndex: uint16 bufGroup: uint16
type InnerSqeSplice = object spliceFdIn: uint32 fileIndex: uint32 addrLen: InnerSqeSplicePadAddrLen
type InnerSqeCmd = object addr3: pointer pad2: array[0..1, uint64] cmd: uint8
type Op = enum OP_NOP = (0, "OP_NOP") OP_READV = (1, "OP_READV") OP_WRITEV = (2, "OP_WRITEV") OP_FSYNC = (3, "OP_FSYNC") OP_READ_FIXED = (4, "OP_READ_FIXED") OP_WRITE_FIXED = (5, "OP_WRITE_FIXED") OP_POLL_ADD = (6, "OP_POLL_ADD") OP_POLL_REMOVE = (7, "OP_POLL_REMOVE") OP_SYNC_FILE_RANGE = (8, "OP_SYNC_FILE_RANGE") OP_SENDMSG = (9, "OP_SENDMSG") OP_RECVMSG = (10, "OP_RECVMSG") OP_TIMEOUT = (11, "OP_TIMEOUT") OP_TIMEOUT_REMOVE = (12, "OP_TIMEOUT_REMOVE") OP_ACCEPT = (13, "OP_ACCEPT") OP_ASYNC_CANCEL = (14, "OP_ASYNC_CANCEL") OP_LINK_TIMEOUT = (15, "OP_LINK_TIMEOUT") OP_CONNECT = (16, "OP_CONNECT") OP_FALLOCATE = (17, "OP_FALLOCATE") OP_OPENAT = (18, "OP_OPENAT") OP_CLOSE = (19, "OP_CLOSE") OP_FILES_UPDATE = (20, "OP_FILES_UPDATE") OP_STATX = (21, "OP_STATX") OP_READ = (22, "OP_READ") OP_WRITE = (23, "OP_WRITE") OP_FADVISE = (24, "OP_FADVISE") OP_MADVISE = (25, "OP_MADVISE") OP_SEND = (26, "OP_SEND") OP_RECV = (27, "OP_RECV") OP_OPENAT2 = (28, "OP_OPENAT2") OP_EPOLL_CTL = (29, "OP_EPOLL_CTL") OP_SPLICE = (30, "OP_SPLICE") OP_PROVIDE_BUFFERS = (31, "OP_PROVIDE_BUFFERS") OP_REMOVE_BUFFERS = (32, "OP_REMOVE_BUFFERS") OP_TEE = (33, "OP_TEE") OP_SHUTDOWN = (34, "OP_SHUTDOWN") OP_RENAMEAT = (35, "OP_RENAMEAT") OP_UNLINKAT = (36, "OP_UNLINKAT") OP_MKDIRAT = (37, "OP_MKDIRAT") OP_SYMLINKAT = (38, "OP_SYMLINKAT") OP_LINKAT = (39, "OP_LINKAT") OP_MSG_RING = (40, "OP_MSG_RING") OP_FSETXATTR = (41, "OP_FSETXATTR") OP_SETXATTR = (42, "OP_SETXATTR") OP_FGETXATTR = (43, "OP_FGETXATTR") OP_GETXATTR = (44, "OP_GETXATTR") OP_SOCKET = (45, "OP_SOCKET") OP_URING_CMD = (46, "OP_URING_CMD") OP_SEND_ZC = (47, "OP_SEND_ZC") OP_SENDMSG_ZC = (48, "OP_SENDMSG_ZC") OP_LAST = (49, "OP_LAST")
func dollar`.Op(e: Op): stringtype InnerSqeOffset = object off: int64 addr2: pointer cmdOp: uint32 pad1: int64
type InnerSqeAddr = object addr: pointer spliceOffIn: int64
type Sqe = object opcode: Op flags: set[SqeFlag] ioprio: set[IoprioFlag] fd: int32 off: InnerSqeOffset addr: InnerSqeAddr len: int32 opFlags: InnerSqeFlags userData: pointer buf: InnerSqeBuf personality: uint16 splice: InnerSqeSplice cmd: InnerSqeCmd
type CqeFlag = enum CQE_F_BUFFER = (0, "CQE_F_BUFFER") CQE_F_MORE = (1, "CQE_F_MORE") CQE_F_SOCK_NONEMPTY = (2, "CQE_F_SOCK_NONEMPTY") CQE_F_NOTIF = (3, "CQE_F_NOTIF")
func dollar`.CqeFlag(e: CqeFlag): stringtype CqeFlags = set[CqeFlag]type Cqe = object userData: uint64 res: int32 flags: set[CqeFlag]
type SetupFlag = enum SETUP_IOPOLL = (0, "SETUP_IOPOLL") SETUP_SQPOLL = (1, "SETUP_SQPOLL") SETUP_SQ_AFF = (2, "SETUP_SQ_AFF") SETUP_CQSIZE = (3, "SETUP_CQSIZE") SETUP_CLAMP = (4, "SETUP_CLAMP") SETUP_ATTACH_WQ = (5, "SETUP_ATTACH_WQ") SETUP_R_DISABLED = (6, "SETUP_R_DISABLED") SETUP_SUBMIT_ALL = (7, "SETUP_SUBMIT_ALL") SETUP_COOP_TASKRUN = (8, "SETUP_COOP_TASKRUN") SETUP_TASKRUN = (9, "SETUP_TASKRUN") SETUP_SQE128 = (10, "SETUP_SQE128") SETUP_CQE32 = (11, "SETUP_CQE32") SETUP_SINGLE_ISSUER = (12, "SETUP_SINGLE_ISSUER") SETUP_DEFER_TASKRUN = (13, "SETUP_DEFER_TASKRUN")
func dollar`.SetupFlag(e: SetupFlag): stringtype SetupFlags = set[SetupFlag]type Feature = enum FEAT_SINGLE_MMAP = (0, "FEAT_SINGLE_MMAP") FEAT_NODROP = (1, "FEAT_NODROP") FEAT_SUBMIT_STABLE = (2, "FEAT_SUBMIT_STABLE") FEAT_RW_CUR_POS = (3, "FEAT_RW_CUR_POS") FEAT_CUR_PERSONALITY = (4, "FEAT_CUR_PERSONALITY") FEAT_FAST_POLL = (5, "FEAT_FAST_POLL") FEAT_POLL_32BITS = (6, "FEAT_POLL_32BITS") FEAT_SQPOLL_NONFIXED = (7, "FEAT_SQPOLL_NONFIXED") FEAT_EXT_ARG = (8, "FEAT_EXT_ARG") FEAT_NATIVE_WORKERS = (9, "FEAT_NATIVE_WORKERS") FEAT_RSRC_TAGS = (10, "FEAT_RSRC_TAGS") FEAT_CQE_SKIP = (11, "FEAT_CQE_SKIP") FEAT_LINKED_FILE = (12, "FEAT_LINKED_FILE") FEAT_REG_REG_RING = (13, "FEAT_REG_REG_RING")
func dollar`.Feature(e: Feature): stringtype Features = set[Feature]type SqringOffsets = object head: uint32 tail: uint32 ringMask: uint32 ringEntries: uint32 flags: uint32 dropped: uint32 array: uint32 resv1: uint32 resv2: uint64
type SqringFlag = enum SQ_NEED_WAKEUP = (0, "SQ_NEED_WAKEUP") SQ_CQ_OVERFLOW = (1, "SQ_CQ_OVERFLOW") SQ_TASKRUN = (2, "SQ_TASKRUN")
func dollar`.SqringFlag(e: SqringFlag): stringtype SqringFlags = set[SqringFlag]type CqringOffsets = object head: uint32 tail: uint32 ringMask: uint32 ringEntries: uint32 overflow: uint32 cqes: uint32 flags: uint32 resv1: uint32 resv2: uint64
type CqringFlag = enum CQ_EVENTFD_DISABLED = (0, "CQ_EVENTFD_DISABLED")
func dollar`.CqringFlag(e: CqringFlag): stringtype CqringFlags = set[CqringFlag]type Params = object sqEntries: uint32 cqEntries: uint32 flags: set[SetupFlag] sqThreadCpu: uint32 sqThreadIdle: uint32 features: set[Feature] wqFd: uint32 resv: array[0..2, uint32] sqOff: SqringOffsets cqOff: CqringOffsets
type EnterFlag = enum ENTER_GETEVENTS = (0, "ENTER_GETEVENTS") ENTER_SQ_WAKEUP = (1, "ENTER_SQ_WAKEUP") ENTER_SQ_WAIT = (2, "ENTER_SQ_WAIT") ENTER_EXT_ARG = (3, "ENTER_EXT_ARG") ENTER_REGISTERED_RING = (4, "ENTER_REGISTERED_RING")
func dollar`.EnterFlag(e: EnterFlag): stringtype EnterFlags = set[EnterFlag]type RegisterOp = enum REGISTER_BUFFERS = (0, "REGISTER_BUFFERS") UNREGISTER_BUFFERS = (1, "UNREGISTER_BUFFERS") REGISTER_FILES = (2, "REGISTER_FILES") UNREGISTER_FILES = (3, "UNREGISTER_FILES") REGISTER_EVENTFD = (4, "REGISTER_EVENTFD") UNREGISTER_EVENTFD = (5, "UNREGISTER_EVENTFD") REGISTER_FILES_UPDATE = (6, "REGISTER_FILES_UPDATE") REGISTER_EVENTFD_ASYNC = (7, "REGISTER_EVENTFD_ASYNC") REGISTER_PROBE = (8, "REGISTER_PROBE") REGISTER_PERSONALITY = (9, "REGISTER_PERSONALITY") UNREGISTER_PERSONALITY = (10, "UNREGISTER_PERSONALITY") REGISTER_RESTRICTIONS = (11, "REGISTER_RESTRICTIONS") REGISTER_ENABLE_RINGS = (12, "REGISTER_ENABLE_RINGS") REGISTER_FILES2 = (13, "REGISTER_FILES2") REGISTER_FILES_UPDATE2 = (14, "REGISTER_FILES_UPDATE2") REGISTER_BUFFERS2 = (15, "REGISTER_BUFFERS2") REGISTER_BUFFERS_UPDATE = (16, "REGISTER_BUFFERS_UPDATE") REGISTER_IOWQ_AFF = (17, "REGISTER_IOWQ_AFF") UNREGISTER_IOWQ_AFF = (18, "UNREGISTER_IOWQ_AFF") REGISTER_IOWQ_MAX_WORKERS = (19, "REGISTER_IOWQ_MAX_WORKERS") REGISTER_RING_FDS = (20, "REGISTER_RING_FDS") UNREGISTER_RING_FDS = (21, "UNREGISTER_RING_FDS") REGISTER_PBUF_RING = (22, "REGISTER_PBUF_RING") UNREGISTER_PBUF_RING = (23, "UNREGISTER_PBUF_RING") REGISTER_SYNC_CANCEL = (24, "REGISTER_SYNC_CANCEL") REGISTER_FILE_ALLOC_RANGE = (25, "REGISTER_FILE_ALLOC_RANGE") REGISTER_LAST = (26, "REGISTER_LAST")
func dollar`.RegisterOp(e: RegisterOp): stringtype RsrcRegister = object nr: uint32 flags: uint32 resv2: uint64 data: uint64 tags: uint64
type RsrcUpdate = object offset: uint32 resv: uint32 data: uint64
type RsrcUpdate2 = object offset: uint32 resv: uint32 data: uint64 tags: uint64 nr: uint32 resv2: uint32
type NotificationSlot = object tag: uint64 resv: array[0..2, uint64]
type NotificationRegister = object nrSlots: uint32 resv: uint32 resv2: uint64 data: uint64 resv3: uint64
type ProbeOp = object op: uint8 resv: uint8 flags: uint16 resv2: uint32
type Probe = object lastOp: uint8 opsLen: uint8 resv: uint16 resv2: array[0..2, uint32] ops: ptr ProbeOp not nil
type Restriction = object opcode: RestrictionOp registerOp: uint8 sqeOp: uint8 sqeFlags: uint8 resv: uint8 resv2: array[0..2, uint32]
type RestrictionOp = enum RESTRICTION_REGISTER_OP = (0, "RESTRICTION_REGISTER_OP") RESTRICTION_SQE_OP = (1, "RESTRICTION_SQE_OP") RESTRICTION_SQE_FLAGS_ALLOWED = (2, "RESTRICTION_SQE_FLAGS_ALLOWED") RESTRICTION_SQE_FLAGS_REQUIRED = (3, "RESTRICTION_SQE_FLAGS_REQUIRED") RESTRICTION_LAST = (4, "RESTRICTION_LAST")
func dollar`.RestrictionOp(e: RestrictionOp): stringtype Buf = object addr: uint64 len: uint32 bid: uint16 resv: uint16
type BufRing = object resv1: uint64 resv2: uint32 resv3: uint16 tail: uint16 bufs: UncheckedArray[Buf]
type BufReg = object ringAddr: uint64 ringEntries: uint32 bgid: uint16 pad: uint16 resv: array[0..2, uint64]
type GeteventsArg = object sigmask: uint64 sigmaskSz: uint32 pad: uint32 ts: uint64
type SyncCancelReg = object addr: uint64 fd: int32 flags: set[AsyncCancelFlag] timeout: Timespec pad: array[0..3, uint64]
type FileIndexRange = object off: uint32 len: uint32 resv: uint64
type RecvmsgOut = object namelen: uint32 controllen: uint32 payloadlen: uint32 flags: set[MsgFlag]
const STATX_BASIC_STATS: set[StatxField]const STATX_ALL: set[StatxField]const FILE_INDEX_ALLOC: uint64const URING_CMD_FIXED: uint64const TIMEOUT_CLOCK_MASK: set[TimeoutFlag]const TIMEOUT_UPDATE_MASK: set[TimeoutFlag]const SPLICE_F_FD_IN_FIXED: uint64const NOTIF_USAGE_ZC_COPIED: uint64const ACCEPT_MULTISHOT: uint64const CQE_BUFFER_SHIFT: int64const OFF_SQ_RING: int64const OFF_CQ_RING: int64const OFF_SQES: int64const REGISTER_USE_REGISTERED_RING: uint64const IO_WQ_BOUND: int64const IO_WQ_UNBOUND: int64const RSRC_REGISTER_SPARSE: uint64const REGISTER_FILES_SKIP: int64const OP_SUPPORTED: uint64proc setup(entries: int32; params: ptr Params not nil): int32proc enter(fd: int32; toSubmit: int32; minComplete: int32; flags: set[EnterFlag]; sig: pointer; sz: int32): int32sigpoints to a kernel sigset (8 bytes on Linux) or is nil.proc register(fd: int32; op: RegisterOp; arg: pointer; nr_args: int32): int32type SqRing = object flags: ptr set[SqringFlag] not nil dropped: pointer not nil array: pointer not nil sqes: ptr Sqe not nil sqesLen: int64 sqeTail: uint32 sqeHead: uint32
type CqRing = object flags: ptr set[CqringFlag] not nil overflow: ptr int64 not nil cqes: pointer not nil
type Queue = object params: ptr Params not nil fd: int32 cq: CqRing sq: SqRing
proc teardown(queue: var Queue)proc newQueue(sqEntries: int64; flags: set[SetupFlag]; sqThreadCpu: int64; sqThreadIdle: int64; wqFd: int64; cqEntries: int64): Queueproc getSqe(queue: var Queue): ptr SqeReturn an sqe to fill. Application must later call queue.submit() when it's ready to tell the kernel about it. The caller may call this function multiple times before calling queue.submit(). Returns a vacant sqe, or nil if we're full.
proc submit(queue: var Queue; waitNr: uint64): int64Submit sqes acquired from queue.getSqe() to the kernel. Returns number of sqes submitted
proc hasExtArg(queue: var Queue): boolCan this ring's
io_uring_entercarry a timeout? Linux 5.11 and up. Without it there is no way to bound a wait from inside the ring, and a caller that must not block forever has to stay in the non-blocking path.proc submitAndWait(queue: var Queue; waitNr: uint64; ts: ptr Timespec): int64Submit, then WAIT in the kernel for
waitNrcompletions, giving up afterts(a RELATIVE duration;nilwaits indefinitely). One syscall for both halves — which is the point:submitnever blocks, so a caller that wants to sleep until something happens otherwise sleeps somewhere else, and a completion arriving a microsecond into that nap waits out the rest of it.Needs
FEAT_EXT_ARG; askhasExtArgfirst.A timeout is not an error here:
ETIMEcomes back as0, and so doEINTR,EAGAINandEBUSY. In every one of those cases the caller's next move is the same — read whatever CQEs are there — so a raise would only be something to catch and discard.proc sqReady(queue: var Queue): uint32Returns 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 iouringsq_ready in liburing.
proc cqReady(queue: var Queue): uint32Returns 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 iouringcq_ready in liburing.
proc copyCqes(queue: var Queue; waitNr: uint64): seqCopies as many CQEs as are ready. If none are available, enters into the kernel to wait for at most
wait_nrCQEs. 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 cqeseen(), avoiding idempotency bugs. Faster, because we can now amortize the atomic store release tocq.headacross the batch. See https://github.com/axboe/liburing/issues/103#issuecomment-686665007. Matches the implementation of iouringpeekbatch_cqe() in liburing, but supports waiting.proc copyCqes(queue: var Queue; cqes: openArray; waitNr: uint64): int64same as copyCqes(queue, waitNr) but copy cqes to your array returns copied cqe count
Copies at most
cqes.len; the rest stay in the ring for the next call, which is whatio_uring_peek_batch_cqe(ring, cqes, count)does with itscount. Without the clamp this writescqReadyentries into the caller's array whatever its size — andcopyCqesToSeqdoes it withcopyMem, so a fixed-size destination is a straight overflow the moment more completions are ready than it can hold. That needs no unusual workload, just enough concurrent operations: the ring's own backend passesarray[128, Cqe].proc registerFiles(q: var Queue; fds: seq): int64Registers 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, IOSQEFIXEDFILE 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.
proc registerFilesUpdate(q: var Queue; offset: int64; fds: seq): int64Updates 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.proc unregisterFiles(q: var Queue): int64Unregisters all registered file descriptors previously associated with the ring.
proc registerEventFd(q: var Queue; fd: int32): int64Registers 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.
proc registerEventFdAsync(q: var Queue; fd: int32): int64Registers 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.
proc unregisterEventFd(q: var Queue): int64Unregister the registered eventfd file descriptor.
proc registerBuffers(q: var Queue; buffers: seq): int64Registers an array of buffers for use with
read_fixedandwrite_fixed. known issues:- EOPNOTSUPP
User buffers point to file-backed memory. error occured then you try to pass pointer allocated on stack use alloc or alloc0
proc unregisterBuffers(q: var Queue): int64Unregister the registered buffers.
proc setUserData(sqe: ptr Sqe not nil; userData: T): ptr Sqe not nilproc linkNext(sqe: ptr Sqe not nil): ptr Sqe not nilproc drainPrevious(sqe: ptr Sqe not nil): ptr Sqe not nilproc nop(sqe: ptr Sqe not nil): ptr Sqe not nilproc fsync(sqe: ptr Sqe not nil; fd: int32; flags: set[FsyncFlag]): ptr Sqe not nilproc fallocate(sqe: ptr Sqe not nil; fd: int32; mode: FileMode; offset: int64; len: int64): ptr Sqe not nilproc statx(sqe: ptr Sqe not nil; fd: int32; path: var string; flags: uint32; mask: set[StatxField]; buf: ptr Stat not nil): ptr Sqe not nilflagsstays a rawAT_*word: those bits start atAT_SYMLINK_NOFOLLOW(0x100) with nothing below them, so they do not form a set of enum.proc read(sqe: ptr Sqe not nil; fd: int32; buffer: pointer not nil; len: int64; offset: int64): ptr Sqe not nilproc read(sqe: ptr Sqe not nil; fd: int32; group_id: uint16; len: int64; offset: int64): ptr Sqe not nilproc readv(sqe: ptr Sqe not nil; fd: int32; iovecs: seq; offset: int64): ptr Sqe not nilproc readv(sqe: ptr Sqe not nil; fd: int32; iovec: ptr IOVec not nil; offset: int64): ptr Sqe not nilproc read_fixed(sqe: ptr Sqe not nil; fd: int32; iovec: IOVec; offset: int64; bufferIndex: int64): ptr Sqe not nilproc write(sqe: ptr Sqe not nil; fd: int32; buffer: pointer not nil; len: int64; offset: int64): ptr Sqe not nilproc write(sqe: ptr Sqe not nil; fd: int32; str: var string; offset: int64): ptr Sqe not nilproc writev(sqe: ptr Sqe not nil; fd: int32; iovecs: seq; offset: int64): ptr Sqe not nilproc write_fixed(sqe: ptr Sqe not nil; fd: int32; iovec: IOVec; offset: int64; bufferIndex: int64): ptr Sqe not nilproc accept(sqe: ptr Sqe not nil; sock: int32; addr: ptr SockAddr not nil; addrLen: ptr uint32 not nil; flags: int32): ptr Sqe not nilproc accept_multishot(sqe: ptr Sqe not nil; sock: int32; addr: ptr SockAddr not nil; addrLen: ptr uint32 not nil; flags: int32): ptr Sqe not nilproc connect(sqe: ptr Sqe not nil; sock: int32; addr: ptr SockAddr not nil; addrLen: uint32): ptr Sqe not nilproc epoll_ctl(sqe: ptr Sqe not nil; epfd: int32; fd: int32; op: uint32; ev: ptr EpollEvent not nil): ptr Sqe not nilproc toPollEvents(mask: uint32): set[PollEvent]Reinterpret a raw poll(2) mask — such as the
resanOP_POLL_ADDcompletion reports — as a set. Bits abovePOLL_RDHUPare dropped: the kernel does not set them for a poll, and keeping them would leave the set holding values that are notPollEvents.proc poll_add(sqe: ptr Sqe not nil; fd: int32; events: set[PollEvent]): ptr Sqe not nilSingle-shot
OP_POLL_ADD: completes once with the fired poll events, then disarms until re-armed. Matches liburing's iouringpreppolladd, which stores the mask in the poll32_events field.proc poll_multi(sqe: ptr Sqe not nil; fd: int32; events: set[PollEvent]): ptr Sqe not nilMultishot
OP_POLL_ADD: stays armed and completes on every readiness edge.proc poll_remove(sqe: ptr Sqe not nil; target_user_data: UserData): ptr Sqe not nilproc poll_update(sqe: ptr Sqe not nil; oldUserData: UserData; newUserData: UserData; events: set[PollEvent]; flags: set[PollFlag]): ptr Sqe not nilflagssays what to update (POLL_UPDATE_EVENTS/POLL_UPDATE_USER_DATA); it travels inlen, which is where the kernel reads theIORING_POLL_*bits.proc recv(sqe: ptr Sqe not nil; sock: int32; buffer: pointer not nil; len: int64; flags: set[MsgFlag]): ptr Sqe not nilproc recv_multishot(sqe: ptr Sqe not nil; sock: int32; buffer: pointer not nil; len: int64; flags: set[MsgFlag]): ptr Sqe not nilproc send(sqe: ptr Sqe not nil; sock: int32; buffer: pointer not nil; len: int64; flags: set[MsgFlag]): ptr Sqe not nilproc send(sqe: ptr Sqe not nil; sock: int32; str: var string; flags: set[MsgFlag]): ptr Sqe not nilproc send_zc(sqe: ptr Sqe not nil; sock: int32; buffer: pointer not nil; len: int64; flags: set[MsgFlag]; zcFlags: set[IoprioFlag]; buf_index: uint64): ptr Sqe not nilproc recvmsg(sqe: ptr Sqe not nil; sock: int32; msghdr: ptr Tmsghdr not nil; flags: set[MsgFlag]): ptr Sqe not nilproc recvmsg_multishot(sqe: ptr Sqe not nil; sock: int32; msghdr: ptr Tmsghdr not nil; flags: set[MsgFlag]): ptr Sqe not nilproc sendmsg(sqe: ptr Sqe not nil; sock: int32; msghdr: ptr Tmsghdr not nil; flags: set[MsgFlag]): ptr Sqe not nilproc sendmsg_zc(sqe: ptr Sqe not nil; sock: int32; msghdr: ptr Tmsghdr not nil; flags: set[MsgFlag]): ptr Sqe not nilproc openat(sqe: ptr Sqe not nil; dfd: int32; path: var string; flags: int32; mode: set[FilePermission]): ptr Sqe not nilproc close(sqe: ptr Sqe not nil; fd: T): ptr Sqe not nilproc renameat(sqe: ptr Sqe not nil; oldDirFd: int32; oldPath: var string; newDirFd: int32; newPath: var string; flags: set[RenameFlag]): ptr Sqe not nilproc unlinkat(sqe: ptr Sqe not nil; dirFd: int32; path: var string; flags: uint32): ptr Sqe not nilproc mkdirat(sqe: ptr Sqe not nil; dirFd: int32; path: var string; mode: uint32): ptr Sqe not nilproc symlinkat(sqe: ptr Sqe not nil; target: var string; newDirFd: int32; linkPath: var string): ptr Sqe not nilproc linkat(sqe: ptr Sqe not nil; oldDirFd: int32; oldPath: var string; newDirFd: int32; newPath: var string; flags: uint32): ptr Sqe not nilproc timeout(sqe: ptr Sqe not nil; ts: ptr Timespec not nil; count: uint32; flags: set[TimeoutFlag]): ptr Sqe not nilproc timeout_remove(sqe: ptr Sqe not nil; timeout_user_data: pointer not nil; flags: set[TimeoutFlag]): ptr Sqe not nilproc link_timeout(sqe: ptr Sqe not nil; ts: Timespec; flags: set[TimeoutFlag]): ptr Sqe not nilproc cancel(sqe: ptr Sqe not nil; cancelUserData: T; flags: set[AsyncCancelFlag]): ptr Sqe not nilproc cancelFd(sqe: ptr Sqe not nil; fd: int32): ptr Sqe not nilCancel every still-in-flight op submitted against
fd(IORINGASYNCCANCELFD), as opposed tocancel, which matches a single op by its userdata. Used when a fd is being closed so the kernel does not later complete into a slot index that the arena has since freed and reused for something else.proc shutdown(sqe: ptr Sqe not nil; sockfd: int32; how: ShutdownHow): ptr Sqe not nilproc provide_buffers(sqe: ptr Sqe not nil; buffers: pointer not nil; bufferSize: int64; buffersCount: int64; groupId: uint64; bufferId: uint64): ptr Sqe not nilproc remove_buffers(sqe: ptr Sqe not nil; buffersCount: int64; groupId: uint64): ptr Sqe not nilproc sync_file_range(sqe: ptr Sqe not nil; fd: int32; len: int64; flags: set[SyncFileRangeFlag]; offset: int64): ptr Sqe not nilproc files_update(sqe: ptr Sqe not nil; fds: seq; offset: int64): ptr Sqe not nilproc fadvice(sqe: ptr Sqe not nil; fd: int32; len: int64; advice: int64; offset: int64): ptr Sqe not nilproc madvice(sqe: ptr Sqe not nil; addr: pointer not nil; len: int64; advice: int64): ptr Sqe not nilproc splice(sqe: ptr Sqe not nil; fd_in: int32; off_in: int64; fd_out: int32; off_out: int64; len: int64; flags: set[SpliceFlag]; fixed: bool): ptr Sqe not nilproc tee(sqe: ptr Sqe not nil; fd_in: int32; fd_out: int32; len: int64; flags: set[SpliceFlag]; fixed: bool): ptr Sqe not nilproc msg_ring(sqe: ptr Sqe not nil; ring_fd: int32; res: int64; user_data: uint64; user_flags: uint32; opcode_flags: set[MsgRingOpFlag]): ptr Sqe not nilproc fsetxattr(sqe: ptr Sqe not nil; fd: int32; name: var string; value: var string; flags: set[XattrFlag]): ptr Sqe not nilproc setxattr(sqe: ptr Sqe not nil; name: var string; value: var string; path: var string; flags: set[XattrFlag]): ptr Sqe not nilproc fgetxattr(sqe: ptr Sqe not nil; fd: int32; name: var string; buf: pointer not nil; len: int64): ptr Sqe not nilproc getxattr(sqe: ptr Sqe not nil; name: var string; buf: pointer not nil; len: int64; path: var string): ptr Sqe not nilproc socket(sqe: ptr Sqe not nil; domain: Domain; type: SockType; protocol: Protocol; flags: int64): ptr Sqe not nil