From fa6b6d222400eb495fe132f813adc274e5fb4d31 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Tue, 18 May 2021 19:03:04 -0400 Subject: [PATCH] linux::io_uring: add result and get_user CQE funcs Also moves the CQE code into its own file. Signed-off-by: Drew DeVault --- io_uring/cqe.ha | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++++ io_uring/queue.ha | 79 ----------------------------------------------------- io_uring/sqe.ha | 4 ++-- diff --git a/io_uring/cqe.ha b/io_uring/cqe.ha new file mode 100644 index 0000000000000000000000000000000000000000..9705b4ba94ba6b4da50fe33bd1318d8b0eab81e8 --- /dev/null +++ b/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/io_uring/queue.ha b/io_uring/queue.ha index f71ba7db60acebd3dfaefefe4886a610247fb46d..0e80937a658bb1cb202aaeb845ab24c426b29d3f 100644 --- a/io_uring/queue.ha +++ b/io_uring/queue.ha @@ -88,82 +88,3 @@ } else { 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/io_uring/sqe.ha b/io_uring/sqe.ha index b6c2070b85a39b43bc2183db9cbace0728aa2ad3..07ff93b559521609b0b9a8101dc5be073dadd8a2 100644 --- a/io_uring/sqe.ha +++ b/io_uring/sqe.ha @@ -28,7 +28,7 @@ }; // 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 @@ // 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); }; -- 2.48.1