From e8af18c426519e1fd46aa15fcfb8c789df5f06a4 Mon Sep 17 00:00:00 2001 From: Runxi Yu Date: Wed, 01 Oct 2025 02:24:23 +0800 Subject: [PATCH] Add some multishot functions --- linux/io_uring/README | 4 ++++ linux/io_uring/sqe.ha | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++++ linux/io_uring/uring.ha | 14 +++++++++++++- diff --git a/linux/io_uring/README b/linux/io_uring/README index d59c8a6491bda5dfc72c20ed3cb0015bbf2dd4fa..e90196f287e4a3d17cf46960b9971475b36c355e 100644 --- a/linux/io_uring/README +++ b/linux/io_uring/README @@ -8,3 +8,7 @@ io_uring_register man pages. This module may be considered to be roughly equivalent to liburing's abstraction layer. + +Note that CQEs from multishot requests will have [[cqe_flags::F_MORE]] set if +the application should expect further CQE entries from the original request. If +not, the request will no longer generate further events. diff --git a/linux/io_uring/sqe.ha b/linux/io_uring/sqe.ha index bafbc367252355122e358e7c542cf439bff9ea2f..835451e78b02e98cc67a6fed70ec846a7dcb6914 100644 --- a/linux/io_uring/sqe.ha +++ b/linux/io_uring/sqe.ha @@ -164,6 +164,17 @@ assert(endian::host == &endian::little); // TODO? sqe.poll32_events = poll_mask: u32; }; +// Prepares a multishot poll operation for an [[sqe]]. +export fn op_poll_add_multishot( + sqe: *sqe, + fd: int, + poll_mask: uint, + flags: sqe_flags... +) void = { + op_poll_add(sqe, fd, poll_mask, flags...); + sqe.length |= rt::IORING_POLL_ADD_MULTI; +}; + // Removes an existing poll request by matching the SQE's user_data field. See // [[sqe_set_data]]. export fn op_poll_remove(sqe: *sqe, user_data: *opaque, flags: sqe_flags...) void = { @@ -197,6 +208,21 @@ preprw(sqe, sqe_op::RECVMSG, fd, msghdr, 0, 0, flags...); sqe.msg_flags = recvmsg_flags; }; +// Prepares a multishot recvmsg operation for an [[sqe]]. +// +// Buffer selection is required. +export fn op_recvmsg_multishot( + sqe: *sqe, + fd: int, + msghdr: *rt::msghdr, + recvmsg_flags: int, + flags: sqe_flags... +) void = { + op_recvmsg(sqe, fd, msghdr, recvmsg_flags, flags...); + assert(recvmsg_flags & rt::MSG_WAITALL == 0); + sqe.ioprio |= rt::IORING_RECV_MULTISHOT; +}; + // Prepares a send operation for an [[sqe]], equivalent to the send(2) system // call. export fn op_send( @@ -227,6 +253,23 @@ preprw(sqe, sqe_op::RECV, fd, buf, count: u32, 0, flags...); sqe.msg_flags = recv_flags; }; +// Prepares a multishot recv operation for an [[sqe]]. +// +// Buffer selection is required. +export fn op_recv_multishot( + sqe: *sqe, + fd: int, + count: size, + recv_flags: int, + flags: sqe_flags... +) void = { + assert(count == 0); + assert(recv_flags & rt::MSG_WAITALL == 0); + preprw(sqe, sqe_op::RECV, fd, null, 0, 0, flags...); + sqe.msg_flags = recv_flags; + sqe.ioprio |= rt::IORING_RECV_MULTISHOT; +}; + // Prepares a timeout operation for an [[sqe]]. "ts" should be a timespec // describing the desired timeout, and "events" may optionally be used to define // a number of completion events to wake after (or zero to wake only after the @@ -241,6 +284,18 @@ flags: sqe_flags... ) void = { preprw(sqe, sqe_op::TIMEOUT, 0, ts, 1, events, flags...); sqe.timeout_flags = to_flags; +}; + +// Prepares a multishot timeout operation for an [[sqe]]. +export fn op_timeout_multishot( + sqe: *sqe, + ts: *rt::timespec, + events: uint, + to_flags: op_timeout_flags, + flags: sqe_flags... +) void = { + op_timeout(sqe, ts, events, to_flags, flags...); + sqe.timeout_flags |= op_timeout_flags::MULTISHOT; }; // Removes an existing timeout request by matching the SQE's user_data field. @@ -297,6 +352,19 @@ ) void = { preprw(sqe, sqe_op::ACCEPT, fd, addr, 0, 0, flags...); sqe.accept_flags = aflags; sqe.addr2 = addrlen; +}; + +// Prepares a multishot accept operation for an [[sqe]]. +export fn op_accept_multishot( + sqe: *sqe, + fd: int, + addr: nullable *rt::sockaddr, + addrlen: nullable *uint, + aflags: uint, + flags: sqe_flags... +) void = { + op_accept(sqe, fd, addr, addrlen, aflags, flags...); + sqe.ioprio |= rt::IORING_ACCEPT_MULTISHOT; }; // Prepares an [[sqe]] operation which opens a file. The path must be a C diff --git a/linux/io_uring/uring.ha b/linux/io_uring/uring.ha index 21f284e20575f10193f6855ffb4524457921055c..0813a16e72b348e614d0f9fc5926f87f7f41a33c 100644 --- a/linux/io_uring/uring.ha +++ b/linux/io_uring/uring.ha @@ -98,9 +98,21 @@ // If set, the timeout will be "absolute", waiting until CLOCK_MONOTONIC // reaches the time defined by the timespec. If unset, it will be // interpted as a duration relative to the I/O submission. ABS = 1 << 0, -// When combined with [[sqe_op::TIMEOUT_REMOVE]], causes the submission to + // When combined with [[sqe_op::TIMEOUT_REMOVE]], causes the submission to // update the timer rather than remove it. UPDATE = 1 << 1, + // Use CLOCK_BOOTTIME instead of CLOCK_MONOTONIC when ABS is set. + // Does not make sense when ABS is unset. + BOOTTIME = 1 << 2, + // Use CLOCK_REALTIME instead of CLOCK_MONOTONIC when ABS is set. + // Does not make sense when ABS is unset. + REALTIME = 1 << 3, + // Targets a linked timeout when used with [[op_timeout_flags::UPDATE]]. + LINK_TIMEOUT_UPDATE = 1 << 4, + // Treat -ETIME completions as success. + ETIME_SUCCESS = 1 << 5, + // Make the timeout generate multiple completions until cancelled. + MULTISHOT = 1 << 6, }; // Flags for a splice operation. -- 2.48.1