commit f1c3648a68335cc5a9065f1e3e4d4bb946102547
parent d9c598e309b7a1cda332a374760e13963df4f6de
Author: Drew DeVault <sir@cmpwn.com>
Date: Fri, 14 May 2021 16:58:01 -1000
linux::uring: flesh out queue somewhat
This still needs porcelain functions.
Signed-off-by: Drew DeVault <sir@cmpwn.com>
Diffstat:
6 files changed, 104 insertions(+), 3 deletions(-)
diff --git a/linux/uring/queue.ha b/linux/uring/queue.ha
@@ -0,0 +1,95 @@
+use errors;
+use rt;
+
+// TODO: Atomics
+
+// Returns the next available [[sqe]] for this [[io_uring]], or null if the
+// queue is full.
+export fn get_sqe(ring: *io_uring) nullable *sqe = {
+ const sq = ring.sq;
+ const head = *sq.khead, next = sq.sqe_tail + 1;
+ if (next - head <= *sq.kring_entries) {
+ let sqe = &sq.sqes[sq.sqe_tail & *sq.kring_mask];
+ sq.sqe_tail = next;
+ return sqe;
+ };
+ return null;
+};
+
+// Like [[get_sqe]], but aborts the program if the queue is full.
+export fn must_get_sqe(ring: *io_uring) *sqe = {
+ return match (get_sqe(ring)) {
+ sq: *sqe => sq,
+ null => abort("I/O submission queue full"),
+ };
+};
+
+fn needs_enter(ring: *io_uring, flags: *enter_flags) bool = {
+ if (ring.flags & setup_flags::IOPOLL == setup_flags::IOPOLL) {
+ return true;
+ };
+
+ if (*ring.sq.kflags & sqring_flags::NEED_WAKEUP == sqring_flags::NEED_WAKEUP) {
+ *flags |= enter_flags::SQ_WAKEUP;
+ return true;
+ };
+
+ return false;
+};
+
+fn needs_flush(ring: *io_uring) bool =
+ *ring.sq.kflags & sqring_flags::CQ_OVERFLOW == sqring_flags::CQ_OVERFLOW;
+
+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 | errors::opaque) = {
+ 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)) {
+ // TODO: EAGAIN
+ abort();
+ };
+ 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/uring/setup.ha b/linux/uring/setup.ha
@@ -1,7 +1,6 @@
use errors;
use rt;
-
// Sets up an io_uring. The params parameter must be initialized with the
// desired flags, sq_thread_cpu, and sq_thread_idle parameters; the remaining
// fields are initialized by the kernel.
diff --git a/linux/uring/sqe.ha b/linux/uring/sqe.ha
@@ -0,0 +1 @@
+// TODO
diff --git a/rt/+linux/syscalls.ha b/rt/+linux/syscalls.ha
@@ -604,7 +604,7 @@ export fn io_uring_setup(entries: u32, params: *void) (int | errno) = {
};
export fn io_uring_register(
- fd: uint,
+ fd: int,
opcode: uint,
arg: nullable *void,
nr_args: uint,
@@ -615,7 +615,7 @@ export fn io_uring_register(
};
export fn io_uring_enter(
- fd: uint,
+ fd: int,
to_submit: uint,
min_complete: uint,
flags: uint,
diff --git a/scripts/gen-stdlib b/scripts/gen-stdlib
@@ -519,7 +519,9 @@ linux() {
linux_uring() {
gen_srcs linux::uring \
+ queue.ha \
setup.ha \
+ sqe.ha \
uring.ha
gen_ssa linux::uring errors
}
diff --git a/stdlib.mk b/stdlib.mk
@@ -698,7 +698,9 @@ $(HARECACHE)/linux/linux.ssa: $(stdlib_linux_srcs) $(stdlib_rt) $(stdlib_format_
# linux::uring
stdlib_linux_uring_srcs= \
+ $(STDLIB)/linux/uring/queue.ha \
$(STDLIB)/linux/uring/setup.ha \
+ $(STDLIB)/linux/uring/sqe.ha \
$(STDLIB)/linux/uring/uring.ha
$(HARECACHE)/linux/uring/linux_uring.ssa: $(stdlib_linux_uring_srcs) $(stdlib_rt) $(stdlib_errors)
@@ -1688,7 +1690,9 @@ $(TESTCACHE)/linux/linux.ssa: $(testlib_linux_srcs) $(testlib_rt) $(testlib_form
# linux::uring
testlib_linux_uring_srcs= \
+ $(STDLIB)/linux/uring/queue.ha \
$(STDLIB)/linux/uring/setup.ha \
+ $(STDLIB)/linux/uring/sqe.ha \
$(STDLIB)/linux/uring/uring.ha
$(TESTCACHE)/linux/uring/linux_uring.ssa: $(testlib_linux_uring_srcs) $(testlib_rt) $(testlib_errors)