commit a9f0ded8a83626ba2c57862eafcb97e4cf9d4c6f
parent b349dadb1c9746791004ca7c7a0dba52aa4faecc
Author: Drew DeVault <sir@cmpwn.com>
Date: Tue, 18 May 2021 19:03:04 -0400
linux::io_uring: add result and get_user CQE funcs
Also moves the CQE code into its own file.
Signed-off-by: Drew DeVault <sir@cmpwn.com>
Diffstat:
5 files changed, 95 insertions(+), 81 deletions(-)
diff --git a/linux/io_uring/cqe.ha b/linux/io_uring/cqe.ha
@@ -0,0 +1,90 @@
+use errors;
+use rt;
+
+// Advances the completion queue by N items.
+export fn cq_advance(ring: *io_uring, n: uint) void = {
+ *ring.cq.khead = *ring.cq.khead + n;
+};
+
+// Call after processing a [[cqe]]. The cqe is returned to the pool and cannot
+// be used by the application again.
+export fn cqe_seen(ring: *io_uring, cqe: *cqe) void = cq_advance(ring, 1);
+
+// Waits until a CQE is available, then returns it. The caller must pass the
+// returned CQE to [[cqe_seen]] to advance the queue.
+export fn wait(ring: *io_uring) (*cqe | error) = {
+ return match (get_cqe(ring, 0, 1)) {
+ err: error => err,
+ cq: nullable *cqe => {
+ assert(cq != null); // XXX: Correct?
+ cq: *cqe;
+ },
+ };
+};
+
+// Peeks the next CQE from the queue and returns it, or null if none are
+// pending. The caller must pass the returned CQE to [[cqe_seen]] to advance the
+// queue.
+export fn peek(ring: *io_uring) (nullable *cqe | error) = get_cqe(ring, 0, 0);
+
+// Returns the result of a [[cqe]], or an error if unsuccessful.
+export fn result(cqe: *cqe) (int | error) =
+ if (cqe.res < 0) rt::wrap_errno(-cqe.res) else cqe.res;
+
+// Gets the user data field of a [[cqe]]. See [[set_user]] for the corresponding
+// SQE function.
+export fn get_user(cqe: *cqe) nullable *void =
+ cqe.user_data: uintptr: nullable *void;
+
+fn peek_cqe(ring: *io_uring) (nullable *cqe, uint) = {
+ let head = *ring.cq.khead;
+ let tail = *ring.cq.ktail;
+ let mask = *ring.cq.kring_mask;
+ let avail = tail - head;
+ if (avail == 0) {
+ return (null, 0);
+ };
+ return (&ring.cq.cqes[head & mask], avail);
+};
+
+fn get_cqe(
+ ring: *io_uring,
+ submit: uint,
+ wait: uint,
+) (nullable *cqe | error) = {
+ let cq: nullable *cqe = null;
+ for (cq == null) {
+ let enter = false, overflow = false;
+ let flags: enter_flags = 0;
+
+ // TODO: tuple destructuring
+ let tup = peek_cqe(ring);
+ let avail = tup.1;
+ cq = tup.0;
+
+ if (cq == null && wait == 0 && submit == 0) {
+ if (!needs_flush(ring)) {
+ return null;
+ };
+ overflow = true;
+ };
+ if (wait > avail || overflow) {
+ flags |= enter_flags::GETEVENTS;
+ enter = true;
+ };
+ if (submit > 0) {
+ needs_enter(ring, &flags);
+ enter = true;
+ };
+ if (!enter) {
+ break;
+ };
+
+ match (rt::io_uring_enter(ring.fd,
+ submit, wait, flags: uint, null)) {
+ err: rt::errno => return errors::errno(err),
+ n: uint => submit -= n,
+ };
+ };
+ return cq;
+};
diff --git a/linux/io_uring/queue.ha b/linux/io_uring/queue.ha
@@ -88,82 +88,3 @@ fn do_submit(
return submitted;
};
};
-
-// Advances the completion queue by N items.
-export fn cq_advance(ring: *io_uring, n: uint) void = {
- *ring.cq.khead = *ring.cq.khead + n;
-};
-
-// Call after processing a [[cqe]]. The cqe is returned to the pool and cannot
-// be used by the application again.
-export fn cqe_seen(ring: *io_uring, cqe: *cqe) void = cq_advance(ring, 1);
-
-// Waits until a CQE is available, then returns it. The caller must pass the
-// returned CQE to [[cqe_seen]] to advance the queue.
-export fn wait(ring: *io_uring) (*cqe | error) = {
- return match (get_cqe(ring, 0, 1)) {
- err: error => err,
- cq: nullable *cqe => {
- assert(cq != null); // XXX: Correct?
- cq: *cqe;
- },
- };
-};
-
-// Peeks the next CQE from the queue and returns it, or null if none are
-// pending. The caller must pass the returned CQE to [[cqe_seen]] to advance the
-// queue.
-export fn peek(ring: *io_uring) (nullable *cqe | error) = get_cqe(ring, 0, 0);
-
-fn peek_cqe(ring: *io_uring) (nullable *cqe, uint) = {
- let head = *ring.cq.khead;
- let tail = *ring.cq.ktail;
- let mask = *ring.cq.kring_mask;
- let avail = tail - head;
- if (avail == 0) {
- return (null, 0);
- };
- return (&ring.cq.cqes[head & mask], avail);
-};
-
-fn get_cqe(
- ring: *io_uring,
- submit: uint,
- wait: uint,
-) (nullable *cqe | error) = {
- let cq: nullable *cqe = null;
- for (cq == null) {
- let enter = false, overflow = false;
- let flags: enter_flags = 0;
-
- // TODO: tuple destructuring
- let tup = peek_cqe(ring);
- let avail = tup.1;
- cq = tup.0;
-
- if (cq == null && wait == 0 && submit == 0) {
- if (!needs_flush(ring)) {
- return null;
- };
- overflow = true;
- };
- if (wait > avail || overflow) {
- flags |= enter_flags::GETEVENTS;
- enter = true;
- };
- if (submit > 0) {
- needs_enter(ring, &flags);
- enter = true;
- };
- if (!enter) {
- break;
- };
-
- match (rt::io_uring_enter(ring.fd,
- submit, wait, flags: uint, null)) {
- err: rt::errno => return errors::errno(err),
- n: uint => submit -= n,
- };
- };
- return cq;
-};
diff --git a/linux/io_uring/sqe.ha b/linux/io_uring/sqe.ha
@@ -28,7 +28,7 @@ fn preprw(
// Sets the user data field of an [[sqe]]. This is copied to the [[cqe]] and can
// be used to correlate a completion event with the original SQE.
-export fn setuser(sqe: *sqe, user_data: *void) void = {
+export fn set_user(sqe: *sqe, user_data: *void) void = {
static assert(size(uintptr) <= size(u64));
sqe.user_data = user_data: uintptr: u64;
};
@@ -151,5 +151,5 @@ export fn poll_add(
// Removes an existing poll request by matching the SQE's user_data field.
export fn poll_remove(sqe: *sqe, user_data: *void, flags: sqe_flags...) void = {
preprw(sqe, op::POLL_REMOVE, -1, null, 0, 0, flags...);
- setuser(sqe, user_data);
+ set_user(sqe, user_data);
};
diff --git a/scripts/gen-stdlib b/scripts/gen-stdlib
@@ -519,6 +519,7 @@ linux() {
linux_io_uring() {
gen_srcs linux::io_uring \
+ cqe.ha \
queue.ha \
register.ha \
setup.ha \
diff --git a/stdlib.mk b/stdlib.mk
@@ -758,6 +758,7 @@ $(HARECACHE)/linux/linux.ssa: $(stdlib_linux_srcs) $(stdlib_rt) $(stdlib_format_
# linux::io_uring
stdlib_linux_io_uring_srcs= \
+ $(STDLIB)/linux/io_uring/cqe.ha \
$(STDLIB)/linux/io_uring/queue.ha \
$(STDLIB)/linux/io_uring/register.ha \
$(STDLIB)/linux/io_uring/setup.ha \
@@ -1811,6 +1812,7 @@ $(TESTCACHE)/linux/linux.ssa: $(testlib_linux_srcs) $(testlib_rt) $(testlib_form
# linux::io_uring
testlib_linux_io_uring_srcs= \
+ $(STDLIB)/linux/io_uring/cqe.ha \
$(STDLIB)/linux/io_uring/queue.ha \
$(STDLIB)/linux/io_uring/register.ha \
$(STDLIB)/linux/io_uring/setup.ha \