hare

The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

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:
Alinux/uring/queue.ha | 95+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mlinux/uring/setup.ha | 1-
Alinux/uring/sqe.ha | 1+
Mrt/+linux/syscalls.ha | 4++--
Mscripts/gen-stdlib | 2++
Mstdlib.mk | 4++++
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)