hare

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

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:
Alinux/io_uring/cqe.ha | 90+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mlinux/io_uring/queue.ha | 79-------------------------------------------------------------------------------
Mlinux/io_uring/sqe.ha | 4++--
Mscripts/gen-stdlib | 1+
Mstdlib.mk | 2++
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 \