From 24fa4ba15bf57850d6558be0ea04a6aef1079943 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Wed, 20 Oct 2021 09:22:31 +0200 Subject: [PATCH] linux::io_uring: implement provide_buffers support Note that this has not been tested. A follow-up patch will integrate this with iobus and it will be tested there. Signed-off-by: Drew DeVault --- io_uring/cqe.ha | 9 +++++++++ io_uring/sqe.ha | 37 +++++++++++++++++++++++++++++++++++++ io_uring/uring.ha | 15 ++++++++++++--- diff --git a/io_uring/cqe.ha b/io_uring/cqe.ha index b278da82625d0eb113fdeac5c2b1f00e1ca587fe..e7b76b3bb54ee9073f0df898a1b9d23f745988d6 100644 --- a/io_uring/cqe.ha +++ b/io_uring/cqe.ha @@ -37,6 +37,15 @@ // SQE function. export fn get_user(cqe: *cqe) nullable *void = cqe.user_data: uintptr: nullable *void; +// Returns the buffer ID used for this [[cqe]] in combination with +// [[set_buffer_select]]. Aborts the program if this CQE was not configured to +// use a buffer pool. +export fn get_buffer_id(cqe: *cqe) u16 = { + assert(cqe.flags & cqe_flags::F_BUFFER > 0, + "get_buffer_id called for CQE without buffer"); + return (cqe.flags: u32 >> CQE_BUFFER_SHIFT): u16; +}; + fn peek_cqe(ring: *io_uring) (nullable *cqe, uint) = { let head = *ring.cq.khead; let tail = *ring.cq.ktail; diff --git a/io_uring/sqe.ha b/io_uring/sqe.ha index eae9f0b0cf7ab4ffffc445bf21a0fa0ecbdbea87..d5926d5bfc7f07d5b03275cf0e2480a2ece932d9 100644 --- a/io_uring/sqe.ha +++ b/io_uring/sqe.ha @@ -33,6 +33,14 @@ static assert(size(uintptr) <= size(u64)); sqe.user_data = user_data: uintptr: u64; }; +// Sets the BUFFER_SELECT flag and sets the desired buffer group. See +// [[provide_buffers]] for configuring buffer groups, and [[get_buffer_id]] to +// retrieve the buffer used from the corresponding [[cqe]]. +export fn set_buffer_select(sqe: *sqe, group: u16) void = { + sqe.flags |= flags::BUFFER_SELECT; + sqe.buf_group = group; +}; + // Prepares a no-op "operation" for an [[sqe]]. export fn nop(sqe: *sqe, flags: flags...) void = { prep(sqe, op::NOP, flags...); @@ -303,3 +311,32 @@ // Prepares an [[sqe]] operation which closes a file descriptor. export fn close(sqe: *sqe, fd: int, flags: flags...) void = { preprw(sqe, op::CLOSE, fd, null, 0, 0, flags...); }; + +// Prepares an [[sqe]] operation which provides a buffer pool to the kernel. +// len(pool) must be equal to nbuf * bufsz. See [[set_buffer_select]] to use +// the buffer pool for a subsequent request. +export fn provide_buffers( + sqe: *sqe, + group: u16, + pool: []u8, + nbuf: size, + bufsz: size, + bufid: u16, + flags: flags... +) void = { + assert(len(pool) == nbuf * bufsz); + preprw(sqe, op::PROVIDE_BUFFERS, nbuf: int, pool: *[*]u8, + bufsz: uint, bufid: uint, flags...); + sqe.buf_group = group; +}; + +// Removes buffers previously registered with [[provide_buffers]]. +export fn remove_buffers( + sqe: *sqe, + nbuf: size, + group: u16, + flags: flags... +) void = { + preprw(sqe, op::REMOVE_BUFFERS, nbuf: int, null, 0, 0, flags...); + sqe.buf_group = group; +}; diff --git a/io_uring/uring.ha b/io_uring/uring.ha index 9c40d30031524bc7bf8e4d3f36053c871d49b7b3..102459d397b4249f3646d1854eefda3efbc8f935 100644 --- a/io_uring/uring.ha +++ b/io_uring/uring.ha @@ -1,17 +1,26 @@ use errors; +// Returned when buffer pool use was configured for an [[sqe]], but there are no +// buffers available. +export type nobuffers = !void; + // All errors which may be returned by this module. -export type error = !errors::error; +export type error = !(errors::error | nobuffers); // Converts an [[error]] into a human-readable string. export fn strerror(err: error) const str = { - return errors::strerror(err); + match (err) { + case nobuffers => + return "Buffer pool exhausted"; + case err: errors::error => + return errors::strerror(err); + }; }; // The maximum value for the first parameter of [[setup]]. export def MAX_ENTRIES: uint = 4096; -def CQE_BUFFER_SHIFT: uint = 16; +def CQE_BUFFER_SHIFT: u32 = 16; def OFF_SQ_RING: u64 = 0; def OFF_CQ_RING: u64 = 0x8000000; def OFF_SQES: u64 = 0x10000000; -- 2.48.1