commit 5fc7e08e6b33bb209510b6fa3770237f31790470
parent 8e70cbf8cfa6051866bb354b2875d99ff23897e0
Author: Drew DeVault <sir@cmpwn.com>
Date: Mon, 18 Apr 2022 14:48:38 +0200
linux::io_uring: remove module
Moved here: https://git.sr.ht/~sircmpwn/hare-linux
Signed-off-by: Drew DeVault <sir@cmpwn.com>
Diffstat:
9 files changed, 0 insertions(+), 1251 deletions(-)
diff --git a/linux/io_uring/README b/linux/io_uring/README
@@ -1,6 +0,0 @@
-The io_uring module provides access to Linux's io_uring subsystem. The
-documentation for this module is somewhat scarce: users are presumed to be
-familiar with io_uring. Thus, it is recommended that a reading of this module is
-paired with the Linux documentation, which may be available from your local
-liburing package under the io_uring_setup, io_uring_enter, and io_uring_register
-man pages.
diff --git a/linux/io_uring/cqe.ha b/linux/io_uring/cqe.ha
@@ -1,114 +0,0 @@
-// License: MPL-2.0
-// (c) 2021 Alexey Yerin <yyp@disroot.org>
-// (c) 2021 Drew DeVault <sir@cmpwn.com>
-// (c) 2021 Eyal Sawady <ecs@d2evs.net>
-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) = {
- match (get_cqe(ring, 0, 1)) {
- case let err: error =>
- return err;
- case let cq: nullable *cqe =>
- return cq as *cqe; // XXX: Correct?
- };
-};
-
-// 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) {
- return cqe.res;
- };
- switch (-cqe.res) {
- case rt::ENOBUFS =>
- return nobuffers;
- case =>
- return errors::errno(rt::wrap_errno(-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;
-
-// 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 = {
- // TODO: Handle ENOBUFS
- 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;
- 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::NONE;
-
- // 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)) {
- case let err: rt::errno =>
- return errors::errno(err);
- case let n: uint =>
- submit -= n;
- };
- };
- return cq;
-};
diff --git a/linux/io_uring/queue.ha b/linux/io_uring/queue.ha
@@ -1,100 +0,0 @@
-// License: MPL-2.0
-// (c) 2021 Alexey Yerin <yyp@disroot.org>
-// (c) 2021 Drew DeVault <sir@cmpwn.com>
-// (c) 2021 Eyal Sawady <ecs@d2evs.net>
-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;
-};
-
-// Returns the next available [[sqe]] for this [[io_uring]], or aborts the
-// program if the queue is full.
-export fn must_get_sqe(ring: *io_uring) *sqe = {
- match (get_sqe(ring)) {
- case null =>
- abort("I/O queue full");
- case let sq: *sqe =>
- return sq;
- };
-};
-
-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;
-
-// Submits queued I/O asynchronously. Returns the number of submissions accepted
-// by the kernel.
-export fn submit(ring: *io_uring) (uint | error) =
- do_submit(ring, flush_sq(ring), 0u);
-
-// Submits queued I/O asynchronously and blocks until at least "wait" events are
-// complete. If setup_flags::IOPOLL was configured for this ring, the meaning of
-// the "wait" parameter is different: a non-zero value will block until at least
-// one event is completed.
-//
-// Returns the number of submissions accepted by the kernel.
-export fn submit_wait(ring: *io_uring, wait: uint) (uint | error) =
- do_submit(ring, flush_sq(ring), wait);
-
-fn flush_sq(ring: *io_uring) uint = {
- let sq = &ring.sq;
- let ktail = *sq.ktail;
- const mask = *sq.kring_mask;
-
- if (sq.sqe_head == sq.sqe_tail) {
- return ktail - *sq.khead;
- };
-
- for (let n = sq.sqe_tail - sq.sqe_head; n > 0; n -= 1u) {
- sq.array[ktail & mask] = sq.sqe_head & mask;
- ktail += 1u;
- sq.sqe_head += 1u;
- };
-
- *sq.ktail = ktail;
- return ktail - *sq.khead;
-};
-
-fn do_submit(
- ring: *io_uring,
- submitted: uint,
- wait: uint,
-) (uint | error) = {
- let flags = enter_flags::GETEVENTS;
- if (needs_enter(ring, &flags) || wait != 0) {
- match (rt::io_uring_enter(ring.fd,
- submitted, wait, flags, null)) {
- case let err: rt::errno =>
- return errors::errno(err);
- case let n: uint =>
- return n;
- };
- } else {
- return submitted;
- };
-};
diff --git a/linux/io_uring/register.ha b/linux/io_uring/register.ha
@@ -1,162 +0,0 @@
-// License: MPL-2.0
-// (c) 2021 Drew DeVault <sir@cmpwn.com>
-// (c) 2021 Eyal Sawady <ecs@d2evs.net>
-use errors;
-use rt;
-use types;
-
-// Registers a set of fixed buffers with an [[io_uring]]. Note that you must
-// call [[unregister_buffers]] before registering a new set of buffers (even if
-// some of them have similar addresses to the old set). The buffers must be
-// anonymous, non-file-backed memory (e.g. the kind returned by alloc or
-// rt::mmap).
-export fn register_buffers(ring: *io_uring, iov: []rt::iovec) (void | error) = {
- assert(len(iov) <= types::UINT_MAX);
- match (rt::io_uring_register(ring.fd, regop::REGISTER_BUFFERS,
- iov: *[*]rt::iovec, len(iov): uint)) {
- case let err: rt::errno =>
- return errors::errno(err);
- case int => void;
- };
-};
-
-// Unregisters all fixed buffers associated with an [[io_uring]].
-export fn unregister_buffers(ring: *io_uring) (void | error) = {
- match (rt::io_uring_register(ring.fd,
- regop::UNREGISTER_BUFFERS, null, 0)) {
- case let err: rt::errno =>
- return errors::errno(err);
- case int => void;
- };
-};
-
-// Registers a set of file descriptors with an [[io_uring]]. The set of files
-// may be sparse, meaning that some are set to -1, to be updated later using
-// [[register_files_update]].
-export fn register_files(ring: *io_uring, files: []int) (void | error) = {
- assert(len(files) <= types::UINT_MAX);
- match (rt::io_uring_register(ring.fd, regop::REGISTER_FILES,
- files: *[*]int, len(files): uint)) {
- case let err: rt::errno =>
- return errors::errno(err);
- case int => void;
- };
-};
-
-// Applies a set of [[files_update]]s to the set of files registered with an
-// [[io_uring]].
-export fn register_files_update(
- ring: *io_uring,
- updates: []files_update,
-) (void | error) = {
- assert(len(updates) <= types::UINT_MAX);
- match (rt::io_uring_register(ring.fd, regop::REGISTER_FILES_UPDATE,
- updates: *[*]files_update, len(updates): uint)) {
- case let err: rt::errno =>
- return errors::errno(err);
- case int => void;
- };
-};
-
-// Unregisters all files associated with an [[io_uring]].
-export fn unregister_files(ring: *io_uring) (void | error) = {
- match (rt::io_uring_register(ring.fd,
- regop::UNREGISTER_FILES, null, 0)) {
- case let err: rt::errno =>
- return errors::errno(err);
- case int => void;
- };
-};
-
-// Registers an eventfd(2) with this [[io_uring]] to be notified of completion
-// events.
-export fn register_eventfd(ring: *io_uring, fd: int) (void | error) = {
- match (rt::io_uring_register(ring.fd,
- regop::REGISTER_EVENTFD, &fd, 1)) {
- case let err: rt::errno =>
- return errors::errno(err);
- case int => void;
- };
-};
-
-// Similar to [[register_eventfd]], but only notifies of events which complet
-// asyncronously.
-export fn register_eventfd_async(ring: *io_uring, fd: int) (void | error) = {
- match (rt::io_uring_register(ring.fd,
- regop::REGISTER_EVENTFD_ASYNC, &fd, 1)) {
- case let err: rt::errno =>
- return errors::errno(err);
- case int => void;
- };
-};
-
-// Unregisters the eventfd(2) associated with this [[io_uring]].
-export fn unregister_eventfd(ring: *io_uring) (void | error) = {
- match (rt::io_uring_register(ring.fd,
- regop::UNREGISTER_EVENTFD, null, 0)) {
- case let err: rt::errno =>
- return errors::errno(err);
- case int => void;
- };
-};
-
-// XXX: This interface is pretty bad. It would be nice to improve on it
-// a bit before making it part of the API.
-//export fn register_probe(ring: *io_uring, out: *probe, nops: size) void = {
-// assert(nops * size(probe_op) <= types::UINT_MAX);
-// match (rt::io_uring_register(ring.fd, regop::REGISTER_PROBE,
-// out, (nops * size(probe)): uint)) {
-// rt::errno => abort("Unexpected io_uring REGISTER_PROBE error"),
-// void => void,
-// };
-//};
-
-// Registers the current process's credentials as a personality with an
-// [[io_uring]], returning an ID. Set the personality field of an [[sqe]] to use
-// that personality for an I/O submission.
-export fn register_personality(ring: *io_uring) int = {
- match (rt::io_uring_register(ring.fd,
- regop::REGISTER_PERSONALITY, null, 0)) {
- case rt::errno =>
- abort("Unexpected io_uring REGISTER_PERSONALITY error");
- case let i: int =>
- return i;
- };
-};
-
-// Unregisters a personality previously configured with
-// [[register_personality]].
-export fn unregister_personality(ring: *io_uring, id: int) (void | error) = {
- match (rt::io_uring_register(ring.fd,
- regop::UNREGISTER_PERSONALITY, null, id: uint)) {
- case let err: rt::errno =>
- return errors::errno(err);
- case int => void;
- };
-};
-
-// Enables submissions for an [[io_uring]] which was started in the disabled
-// state via [[setup_flags::R_DISABLED]]. Future access to this io_uring is
-// subject to any configured restrictions.
-export fn register_enable_rings(ring: *io_uring) (void | error) = {
- match (rt::io_uring_register(ring.fd,
- regop::REGISTER_ENABLE_RINGS, null, 0)) {
- case let err: rt::errno =>
- return errors::errno(err);
- case int => void;
- };
-};
-
-// Registers a restriction for this [[io_uring]], limiting the kinds of future
-// registrations and I/O submissions which are permitted for it. This is only
-// accepted if the [[io_uring]] was set up in a disabled state via
-// [[setup_flags::R_DISABLED]].
-export fn register_restrictions(ring: *io_uring, res: []restriction) (void | error) = {
- assert(len(res) < types::UINT_MAX);
- match (rt::io_uring_register(ring.fd, regop::REGISTER_RESTRICTIONS,
- res: *[*]restriction, len(res): uint)) {
- case let err: rt::errno =>
- return errors::errno(err);
- case int => void;
- };
-};
diff --git a/linux/io_uring/setup.ha b/linux/io_uring/setup.ha
@@ -1,102 +0,0 @@
-// License: MPL-2.0
-// (c) 2021 Drew DeVault <sir@cmpwn.com>
-// (c) 2021 Eyal Sawady <ecs@d2evs.net>
-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.
-export fn setup(entries: u32, params: *params) (io_uring | error) = {
- const fd = match (rt::io_uring_setup(entries, params)) {
- case let err: rt::errno =>
- return errors::errno(err);
- case let fd: int =>
- yield fd;
- };
-
- let uring = io_uring {
- sq = sq { ... },
- cq = cq { ... },
- fd = fd,
- flags = params.flags,
- features = params.features,
- };
- let sq = &uring.sq, cq = &uring.cq;
-
- sq.ring_sz = params.sq_off.array + params.sq_entries * size(uint);
- cq.ring_sz = params.cq_off.cqes + params.cq_entries * size(cqe);
-
- if (uring.features & features::SINGLE_MMAP == features::SINGLE_MMAP) {
- if (cq.ring_sz > sq.ring_sz) {
- sq.ring_sz = cq.ring_sz;
- };
- cq.ring_sz = sq.ring_sz;
- };
-
- sq.ring_ptr = match (rt::mmap(null,
- params.sq_off.array + entries * size(u32),
- rt::PROT_READ | rt::PROT_WRITE,
- rt::MAP_SHARED | rt::MAP_POPULATE,
- fd, OFF_SQ_RING)) {
- case let err: rt::errno =>
- return errors::errno(err);
- case let ptr: *void =>
- yield ptr;
- };
-
- cq.ring_ptr = if (uring.features & features::SINGLE_MMAP == features::SINGLE_MMAP) {
- yield sq.ring_ptr;
- } else match (rt::mmap(null, cq.ring_sz,
- rt::PROT_READ | rt::PROT_WRITE,
- rt::MAP_SHARED | rt::MAP_POPULATE,
- fd, OFF_CQ_RING)) {
- case let err: rt::errno =>
- return errors::errno(err);
- case let ptr: *void =>
- yield ptr;
- };
-
- const ring_ptr = sq.ring_ptr: uintptr;
- sq.khead = (ring_ptr + params.sq_off.head: uintptr): *uint;
- sq.ktail = (ring_ptr + params.sq_off.tail: uintptr): *uint;
- sq.kring_mask = (ring_ptr + params.sq_off.ring_mask: uintptr): *uint;
- sq.kring_entries = (ring_ptr + params.sq_off.ring_entries: uintptr): *uint;
- sq.kflags = (ring_ptr + params.sq_off.flags: uintptr): *sqring_flags;
- sq.kdropped = (ring_ptr + params.sq_off.dropped: uintptr): *uint;
- sq.array = (ring_ptr + params.sq_off.array: uintptr): *[*]uint;
- sq.sqes = match (rt::mmap(null,
- params.sq_entries * size(sqe),
- rt::PROT_READ | rt::PROT_WRITE,
- rt::MAP_SHARED | rt::MAP_POPULATE,
- fd, OFF_SQES)) {
- case let err: rt::errno =>
- return errors::errno(err);
- case let ptr: *void =>
- yield ptr: *[*]sqe;
- };
-
- const ring_ptr = cq.ring_ptr: uintptr;
- cq.khead = (ring_ptr + params.cq_off.head: uintptr): *uint;
- cq.ktail = (ring_ptr + params.cq_off.tail: uintptr): *uint;
- cq.kring_mask = (ring_ptr + params.cq_off.ring_mask: uintptr): *uint;
- cq.kring_entries = (ring_ptr + params.cq_off.ring_entries: uintptr): *uint;
- cq.koverflow = (ring_ptr + params.cq_off.overflow: uintptr): *uint;
- cq.cqes = (ring_ptr + params.cq_off.cqes: uintptr): *[*]cqe;
-
- if (params.cq_off.flags != 0) {
- cq.kflags = (ring_ptr + params.cq_off.flags: uintptr): *cqring_flags;
- };
-
- return uring;
-};
-
-// Frees state associated with an [[io_uring]].
-export fn finish(ring: *io_uring) void = {
- let sq = &ring.sq, cq = &ring.cq;
- rt::munmap(sq.ring_ptr, sq.ring_sz): void;
- if (cq.ring_ptr != null: *void && cq.ring_ptr != sq.ring_ptr) {
- rt::munmap(cq.ring_ptr, cq.ring_sz): void;
- };
- rt::close(ring.fd): void;
-};
diff --git a/linux/io_uring/sqe.ha b/linux/io_uring/sqe.ha
@@ -1,346 +0,0 @@
-// License: MPL-2.0
-// (c) 2021 Alexey Yerin <yyp@disroot.org>
-// (c) 2021 Drew DeVault <sir@cmpwn.com>
-// (c) 2022 Eyal Sawady <ecs@d2evs.net>
-use endian;
-use rt;
-use types;
-
-fn prep(sq: *sqe, op: op, flags: flags...) void = {
- rt::memset(sq, 0, size(sqe));
- sq.opcode = op;
- for (let i = 0z; i < len(flags); i += 1) {
- sq.flags |= flags[i];
- };
-};
-
-fn preprw(
- sqe: *sqe,
- op: op,
- fd: int,
- addr: nullable *void,
- length: uint,
- offs: u64,
- flags: flags...
-) void = {
- prep(sqe, op, flags...);
- sqe.fd = fd;
- sqe.addr = addr;
- sqe.length = length;
- sqe.off = offs;
-};
-
-// 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 set_user(sqe: *sqe, user_data: *void) void = {
- 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...);
-};
-
-// Prepares a vectored read operation for an [[sqe]].
-export fn readv(
- sqe: *sqe,
- fd: int,
- iov: []rt::iovec,
- offs: size,
- flags: flags...
-) void = {
- preprw(sqe, op::READV, fd,
- iov: *[*]rt::iovec, len(iov): uint, offs, flags...);
-};
-
-// Prepares a vectored write operation for an [[sqe]].
-export fn writev(
- sqe: *sqe,
- fd: int,
- iov: []rt::iovec,
- offs: size,
- flags: flags...
-) void = {
- preprw(sqe, op::WRITEV, fd,
- iov: *[*]rt::iovec, len(iov): uint, offs, flags...);
-};
-
-// Prepares a read operation for an [[sqe]].
-export fn read(
- sqe: *sqe,
- fd: int,
- buf: *void,
- count: size,
- offs: u64,
- flags: flags...
-) void = {
- assert(count <= types::U32_MAX);
- preprw(sqe, op::READ, fd, buf, count: u32, offs, flags...);
-};
-
-// Prepares a write operation for an [[sqe]].
-export fn write(
- sqe: *sqe,
- fd: int,
- buf: *void,
- count: size,
- offs: u64,
- flags: flags...
-) void = {
- assert(count <= types::U32_MAX);
- preprw(sqe, op::WRITE, fd, buf, count: u32, offs, flags...);
-};
-
-// Prepares a read for a fixed buffer previously registered with
-// [[register_buffers]]. The buf and count parameters must refer to an address
-// which falls within the buffer referenced by the index parameter.
-export fn read_fixed(
- sqe: *sqe,
- fd: int,
- buf: *void,
- count: size,
- index: u16,
- flags: flags...
-) void = {
- assert(count <= types::U32_MAX);
- preprw(sqe, op::READ_FIXED, fd, buf, count: u32, 0, flags...);
- sqe.buf_index = index;
-};
-
-// Prepares a write for a fixed buffer previously registered with
-// [[register_buffers]]. The buf and count parameters must refer to an address
-// which falls within the buffer referenced by the index parameter.
-export fn write_fixed(
- sqe: *sqe,
- fd: int,
- buf: *void,
- count: size,
- index: u16,
- flags: flags...
-) void = {
- assert(count <= types::U32_MAX);
- preprw(sqe, op::WRITE_FIXED, fd, buf, count: u32, 0, flags...);
- sqe.buf_index = index;
-};
-
-// Prepares an fsync operation for an [[sqe]]. Note that operations are executed
-// in parallel and not are completed in submission order, so an fsync submitted
-// after a write may not cause the write to be accounted for by the fsync unless
-// [[flags::IO_LINK]] is used.
-export fn fsync(
- sqe: *sqe,
- fd: int,
- fsync_flags: fsync_flags,
- flags: flags...
-) void = {
- preprw(sqe, op::FSYNC, fd, null, 0, 0, flags...);
- sqe.fsync_flags = fsync_flags;
-};
-
-// Adds a request to poll a file descriptor for the given set of poll events.
-// This will only happen once, the poll request must be submitted with a new SQE
-// to re-poll the file descriptor later. The caller must call [[set_user]] to
-// provide a user data field in order to use [[poll_remove]] to remove this poll
-// request later.
-export fn poll_add(
- sqe: *sqe,
- fd: int,
- poll_mask: uint,
- flags: flags...
-) void = {
- preprw(sqe, op::POLL_ADD, fd, null, 0, 0, flags...);
- assert(endian::host == &endian::little); // TODO?
- sqe.poll32_events = poll_mask: u32;
-};
-
-// Removes an existing poll request by matching the SQE's user_data field. See
-// [[set_user]].
-export fn poll_remove(sqe: *sqe, user_data: *void, flags: flags...) void = {
- preprw(sqe, op::POLL_REMOVE, -1, null, 0, 0, flags...);
- set_user(sqe, user_data);
-};
-
-// Prepares a sendmsg operation for an [[sqe]], equivalent to the sendmsg(2)
-// system call.
-export fn sendmsg(
- sqe: *sqe,
- fd: int,
- msghdr: *rt::msghdr,
- sendmsg_flags: int,
- flags: flags...
-) void = {
- preprw(sqe, op::SENDMSG, fd, msghdr, 0, 0, flags...);
- sqe.msg_flags = sendmsg_flags;
-};
-
-// Prepares a recvmsg operation for an [[sqe]], equivalent to the recvmsg(2)
-// system call.
-export fn recvmsg(
- sqe: *sqe,
- fd: int,
- msghdr: *rt::msghdr,
- recvmsg_flags: int,
- flags: flags...
-) void = {
- preprw(sqe, op::RECVMSG, fd, msghdr, 0, 0, flags...);
- sqe.msg_flags = recvmsg_flags;
-};
-
-// Prepares a send operation for an [[sqe]], equivalent to the send(2) system
-// call.
-export fn send(
- sqe: *sqe,
- fd: int,
- buf: *void,
- count: size,
- send_flags: int,
- flags: flags...
-) void = {
- assert(count <= types::U32_MAX);
- preprw(sqe, op::SEND, fd, buf, count: u32, 0, flags...);
- sqe.msg_flags = send_flags;
-};
-
-// Prepares a recv operation for an [[sqe]], equivalent to the recv(2) system
-// call.
-export fn recv(
- sqe: *sqe,
- fd: int,
- buf: *void,
- count: size,
- recv_flags: int,
- flags: flags...
-) void = {
- assert(count <= types::U32_MAX);
- preprw(sqe, op::RECV, fd, buf, count: u32, 0, flags...);
- sqe.msg_flags = recv_flags;
-};
-
-// Prepares a timeout operation for an [[sqe]]. "ts" should be a timespec
-// describing the desired timeout, and "events" may optionally be used to define
-// a number of completion events to wake after (or zero to wake only after the
-// timeout expires). The caller must call [[set_user]] to provide a user data
-// field in order to use [[timeout_remove]] to cancel this timeout later.
-export fn timeout(
- sqe: *sqe,
- ts: *rt::timespec,
- events: uint,
- to_flags: timeout_flags,
- flags: flags...
-) void = {
- preprw(sqe, op::TIMEOUT, 0, ts, 1, events, flags...);
- sqe.timeout_flags = to_flags;
-};
-
-// Removes an existing timeout request by matching the SQE's user_data field.
-// See [[set_user]].
-export fn timeout_remove(
- sqe: *sqe,
- user_data: *void,
- to_flags: timeout_flags,
- flags: flags...
-) void = {
- preprw(sqe, op::TIMEOUT_REMOVE, 0, user_data, 0, 0, flags...);
- sqe.timeout_flags = to_flags;
-};
-
-// Updates an existing timeout request by matching the SQE's user_data field.
-// See [[set_user]].
-export fn timeout_update(
- sqe: *sqe,
- user_data: *void,
- ts: *rt::timespec,
- events: uint,
- to_flags: timeout_flags,
- flags: flags...
-) void = {
- preprw(sqe, op::TIMEOUT_REMOVE, 0, user_data, 0, events, flags...);
- sqe.timeout_flags = to_flags | timeout_flags::UPDATE;
- sqe.addr2 = ts;
-};
-
-// Prepares a timeout operation for an [[sqe]] which is linked to the previous
-// SQE, effectively setting an upper limit on how long that SQE can take to
-// complete. "ts" should be a timespec describing the desired timeout. The
-// caller must call [[set_user]] to provide a user data field in order to use
-// [[timeout_remove]] to cancel this timeout later.
-export fn link_timeout(
- sqe: *sqe,
- ts: *rt::timespec,
- to_flags: timeout_flags,
- flags: flags...
-) void = {
- preprw(sqe, op::LINK_TIMEOUT, 0, ts, 1, 0, flags...);
- sqe.timeout_flags = to_flags;
-};
-
-// Prepares a socket accept operation for an [[sqe]]. Equivalent to accept4(2).
-export fn accept(
- sqe: *sqe,
- fd: int,
- addr: nullable *rt::sockaddr,
- addrlen: nullable *uint,
- aflags: uint,
- flags: flags...
-) void = {
- preprw(sqe, op::ACCEPT, fd, addr, 0, 0, flags...);
- sqe.accept_flags = aflags;
- sqe.addr2 = addrlen;
-};
-
-// Prepares an [[sqe]] operation which opens a file. The path must be a C
-// string, i.e. NUL terminated; see [[strings::to_c]].
-export fn openat(
- sqe: *sqe,
- dirfd: int,
- path: *const char,
- oflags: int,
- mode: uint,
- flags: flags...
-) void = {
- preprw(sqe, op::OPENAT, dirfd, path, mode, 0, flags...);
- sqe.open_flags = oflags: u32;
-};
-
-// 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/linux/io_uring/uring.ha b/linux/io_uring/uring.ha
@@ -1,371 +0,0 @@
-// License: MPL-2.0
-// (c) 2021 Alexey Yerin <yyp@disroot.org>
-// (c) 2021 Drew DeVault <sir@cmpwn.com>
-// (c) 2021-2022 Eyal Sawady <ecs@d2evs.net>
-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 | nobuffers);
-
-// Converts an [[error]] into a human-readable string.
-export fn strerror(err: error) const str = {
- match (err) {
- case nobuffers =>
- return "Buffer pool exhausted";
- case let 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: u32 = 16;
-def OFF_SQ_RING: u64 = 0;
-def OFF_CQ_RING: u64 = 0x8000000;
-def OFF_SQES: u64 = 0x10000000;
-
-// An io_uring [[sqe]] operation.
-export type op = enum u8 {
- NOP,
- READV,
- WRITEV,
- FSYNC,
- READ_FIXED,
- WRITE_FIXED,
- POLL_ADD,
- POLL_REMOVE,
- SYNC_FILE_RANGE,
- SENDMSG,
- RECVMSG,
- TIMEOUT,
- TIMEOUT_REMOVE,
- ACCEPT,
- ASYNC_CANCEL,
- LINK_TIMEOUT,
- CONNECT,
- FALLOCATE,
- OPENAT,
- CLOSE,
- FILES_UPDATE,
- STATX,
- READ,
- WRITE,
- FADVISE,
- MADVISE,
- SEND,
- RECV,
- OPENAT2,
- EPOLL_CTL,
- SPLICE,
- PROVIDE_BUFFERS,
- REMOVE_BUFFERS,
- TEE,
-};
-
-// Flags for an [[sqe]].
-export type flags = enum u8 {
- NONE = 0,
- // Use fixed fileset
- FIXED_FILE = 1 << 0,
- // Issue after inflight IO
- IO_DRAIN = 1 << 1,
- // Links next sqe
- IO_LINK = 1 << 2,
- // Like LINK, but stronger
- IO_HARDLINK = 1 << 3,
- // Always go async
- ASYNC = 1 << 4,
- // Select buffer from sqe.buf_group
- BUFFER_SELECT = 1 << 5,
-};
-
-// Flags for an fsync operation.
-export type fsync_flags = enum u32 {
- NONE = 0,
- DATASYNC = 1 << 0,
-};
-
-// Flags for a timeout operation.
-export type timeout_flags = enum u32 {
- NONE = 0,
- // If set, the timeout will be "absolute", waiting until CLOCK_MONOTONIC
- // reaches the time defined by the timespec. If unset, it will be
- // interpted as a duration relative to the I/O submission.
- ABS = 1 << 0,
- // When combined with [[op::TIMEOUT_REMOVE]], causes the submission to
- // update the timer rather than remove it.
- UPDATE = 1 << 1,
-};
-
-// Flags for a splice operation.
-export type splice_flags = enum u32 {
- NONE = 0,
- F_FD_IN_FIXED = 1 << 31,
-};
-
-// Flags for a [[cqe]].
-export type cqe_flags = enum u32 {
- NONE = 0,
- F_BUFFER = 1 << 0,
- F_MORE = 1 << 1,
-};
-
-// A submission queue entry.
-export type sqe = struct {
- opcode: op,
- flags: flags,
- ioprio: u16,
- fd: i32,
- union {
- off: u64,
- addr2: nullable *void,
- },
- union {
- addr: nullable *void,
- splice_off_in: u64,
- },
- length: u32,
- union {
- rw_flags: int,
- fsync_flags: fsync_flags,
- poll_events: u16,
- poll32_events: u32,
- sync_range_flags: u32,
- msg_flags: int,
- timeout_flags: timeout_flags,
- accept_flags: u32,
- cancel_flags: u32,
- open_flags: u32,
- statx_flags: u32,
- fadvise_advice: u32,
- splice_flags: splice_flags,
- },
- user_data: u64,
- union {
- struct {
- union {
- buf_index: u16,
- buf_group: u16,
- },
- personality: u16,
- splice_fd_in: i32,
- },
- pad2: [3]u64,
- },
-};
-
-// A completion queue entry.
-export type cqe = struct {
- user_data: u64,
- res: i32,
- flags: cqe_flags,
-};
-
-// Filled with the offset for mmap(2)
-export type sqring_offsets = struct {
- head: u32,
- tail: u32,
- ring_mask: u32,
- ring_entries: u32,
- flags: u32,
- dropped: u32,
- array: u32,
- resv1: u32,
- resv2: u64,
-};
-
-// Flags for the sq ring.
-export type sqring_flags = enum u32 {
- NONE = 0,
- // Needs io_uring_enter wakeup
- NEED_WAKEUP = 1 << 0,
- // CQ ring is overflown
- CQ_OVERFLOW = 1 << 1,
-};
-
-// Filled with the offset for mmap(2)
-export type cqring_offsets = struct {
- head: u32,
- tail: u32,
- ring_mask: u32,
- ring_entries: u32,
- overflow: u32,
- cqes: u32,
- flags: u32,
- resv1: u32,
- resv2: u64,
-};
-
-// Flags for the cq ring.
-export type cqring_flags = enum u32 {
- NONE = 0,
- EVENTFD_DISABLED = 1 << 0,
-};
-
-// Flags for setup operation.
-export type setup_flags = enum u32 {
- NONE = 0,
- // io_context is polled
- IOPOLL = 1 << 0,
- // SQ poll thread
- SQPOLL = 1 << 1,
- // sq_thread_cpu is valid
- SQ_AFF = 1 << 2,
- // App defines CQ size
- CQSIZE = 1 << 3,
- // Clamp SQ/CQ ring sizes
- CLAMP = 1 << 4,
- // Attach to existing wq
- ATTACH_WQ = 1 << 5,
- // Start with ring disabled
- R_DISABLED = 1 << 6,
-};
-
-// Parameters for [[setup]]. Partially completed by the kernel.
-export type params = struct {
- sq_entries: u32,
- cq_entries: u32,
- flags: setup_flags,
- sq_thread_cpu: u32,
- sq_thread_idle: u32,
- features: features,
- wq_fd: u32,
- resv: [3]u32,
- sq_off: sqring_offsets,
- cq_off: cqring_offsets,
-};
-
-// Features supported by the kernel.
-export type features = enum u32 {
- NONE = 0,
- SINGLE_MMAP = 1 << 0,
- NODROP = 1 << 1,
- SUBMIT_STABLE = 1 << 2,
- RW_CUR_POS = 1 << 3,
- CUR_PERSONALITY = 1 << 4,
- FAST_POLL = 1 << 5,
- POLL_32BITS = 1 << 6,
-};
-
-// Flags for enter operation.
-export type enter_flags = enum uint {
- NONE = 0,
- GETEVENTS = 1 << 0,
- SQ_WAKEUP = 1 << 1,
- SQ_WAIT = 1 << 2,
-};
-
-// Register operations.
-export type regop = enum uint {
- REGISTER_BUFFERS,
- UNREGISTER_BUFFERS,
- REGISTER_FILES,
- UNREGISTER_FILES,
- REGISTER_EVENTFD,
- UNREGISTER_EVENTFD,
- REGISTER_FILES_UPDATE,
- REGISTER_EVENTFD_ASYNC,
- REGISTER_PROBE,
- REGISTER_PERSONALITY,
- UNREGISTER_PERSONALITY,
- REGISTER_RESTRICTIONS,
- REGISTER_ENABLE_RINGS,
-};
-
-// Information for a REGISTER_FILES_UPDATE operation.
-export type files_update = struct {
- offs: u32,
- resv: u32,
- fds: *int,
-};
-
-// Flags for a probe operation.
-export type op_flags = enum u16 {
- NONE = 0,
- SUPPORTED = 1 << 0,
-};
-
-// REGISTER_PROBE operation details.
-export type probe_op = struct {
- op: u8,
- resv: u8,
- flags: op_flags,
- resv2: u32,
-};
-
-// Summary of REGISTER_PROBE results.
-export type probe = struct {
- last_op: u8,
- ops_len: u8,
- resv: u16,
- resv2: [3]u32,
- ops: [*]probe_op,
-};
-
-// Details for a REGISTER_RESTRICTIONS operation.
-export type restriction = struct {
- opcode: resop,
- union {
- register_op: regop,
- sqe_op: op,
- flags: flags,
- },
- resv: u8,
- resv2: [3]u32,
-};
-
-// Opcode for a [[restriction]].
-export type resop = enum u16 {
- NONE = 0,
- // Allow an io_uring_register(2) opcode
- REGISTER_OP = 0,
- // Allow an sqe opcode
- SQE_OP = 1,
- // Allow sqe flags
- SQE_FLAGS_ALLOWED = 2,
- // Require sqe flags (these flags must be set on each submission)
- SQE_FLAGS_REQUIRED = 3,
-};
-
-// State for an io_uring.
-export type io_uring = struct {
- sq: sq,
- cq: cq,
- fd: int,
- flags: setup_flags,
- features: features,
-};
-
-// Submission queue state.
-export type sq = struct {
- khead: *uint,
- ktail: *uint,
- kring_mask: *uint,
- kring_entries: *uint,
- kflags: *sqring_flags,
- kdropped: *uint,
- array: *[*]uint,
- sqes: *[*]sqe,
- sqe_head: uint,
- sqe_tail: uint,
- ring_sz: size,
- ring_ptr: *void,
-};
-
-// Completion queue state.
-export type cq = struct {
- khead: *uint,
- ktail: *uint,
- kring_mask: *uint,
- kring_entries: *uint,
- kflags: *cqring_flags,
- koverflow: *uint,
- cqes: *[*]cqe,
- ring_sz: size,
- ring_ptr: *void,
-};
diff --git a/scripts/gen-stdlib b/scripts/gen-stdlib
@@ -831,17 +831,6 @@ linux_keyctl() {
gen_ssa -plinux linux::keyctl rt errors strings bytes
}
-linux_io_uring() {
- gen_srcs -plinux linux::io_uring \
- cqe.ha \
- queue.ha \
- register.ha \
- setup.ha \
- sqe.ha \
- uring.ha
- gen_ssa -plinux linux::io_uring errors types
-}
-
linux_vdso() {
gen_srcs -plinux linux::vdso \
vdso.ha
@@ -1359,7 +1348,6 @@ hash::fnv
io linux freebsd
linux linux
linux::keyctl linux
-linux::io_uring linux
linux::vdso linux
log
math
diff --git a/stdlib.mk b/stdlib.mk
@@ -466,10 +466,6 @@ stdlib_deps_linux+=$(stdlib_linux_linux)
stdlib_linux_keyctl_linux=$(HARECACHE)/linux/keyctl/linux_keyctl-linux.o
stdlib_deps_linux+=$(stdlib_linux_keyctl_linux)
-# gen_lib linux::io_uring (linux)
-stdlib_linux_io_uring_linux=$(HARECACHE)/linux/io_uring/linux_io_uring-linux.o
-stdlib_deps_linux+=$(stdlib_linux_io_uring_linux)
-
# gen_lib linux::vdso (linux)
stdlib_linux_vdso_linux=$(HARECACHE)/linux/vdso/linux_vdso-linux.o
stdlib_deps_linux+=$(stdlib_linux_vdso_linux)
@@ -1381,21 +1377,6 @@ $(HARECACHE)/linux/keyctl/linux_keyctl-linux.ssa: $(stdlib_linux_keyctl_linux_sr
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nlinux::keyctl \
-t$(HARECACHE)/linux/keyctl/linux_keyctl.td $(stdlib_linux_keyctl_linux_srcs)
-# linux::io_uring (+linux)
-stdlib_linux_io_uring_linux_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 \
- $(STDLIB)/linux/io_uring/sqe.ha \
- $(STDLIB)/linux/io_uring/uring.ha
-
-$(HARECACHE)/linux/io_uring/linux_io_uring-linux.ssa: $(stdlib_linux_io_uring_linux_srcs) $(stdlib_rt) $(stdlib_errors_$(PLATFORM)) $(stdlib_types_$(PLATFORM))
- @printf 'HAREC \t$@\n'
- @mkdir -p $(HARECACHE)/linux/io_uring
- @HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nlinux::io_uring \
- -t$(HARECACHE)/linux/io_uring/linux_io_uring.td $(stdlib_linux_io_uring_linux_srcs)
-
# linux::vdso (+linux)
stdlib_linux_vdso_linux_srcs= \
$(STDLIB)/linux/vdso/vdso.ha
@@ -2454,10 +2435,6 @@ testlib_deps_linux+=$(testlib_linux_linux)
testlib_linux_keyctl_linux=$(TESTCACHE)/linux/keyctl/linux_keyctl-linux.o
testlib_deps_linux+=$(testlib_linux_keyctl_linux)
-# gen_lib linux::io_uring (linux)
-testlib_linux_io_uring_linux=$(TESTCACHE)/linux/io_uring/linux_io_uring-linux.o
-testlib_deps_linux+=$(testlib_linux_io_uring_linux)
-
# gen_lib linux::vdso (linux)
testlib_linux_vdso_linux=$(TESTCACHE)/linux/vdso/linux_vdso-linux.o
testlib_deps_linux+=$(testlib_linux_vdso_linux)
@@ -3407,21 +3384,6 @@ $(TESTCACHE)/linux/keyctl/linux_keyctl-linux.ssa: $(testlib_linux_keyctl_linux_s
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nlinux::keyctl \
-t$(TESTCACHE)/linux/keyctl/linux_keyctl.td $(testlib_linux_keyctl_linux_srcs)
-# linux::io_uring (+linux)
-testlib_linux_io_uring_linux_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 \
- $(STDLIB)/linux/io_uring/sqe.ha \
- $(STDLIB)/linux/io_uring/uring.ha
-
-$(TESTCACHE)/linux/io_uring/linux_io_uring-linux.ssa: $(testlib_linux_io_uring_linux_srcs) $(testlib_rt) $(testlib_errors_$(PLATFORM)) $(testlib_types_$(PLATFORM))
- @printf 'HAREC \t$@\n'
- @mkdir -p $(TESTCACHE)/linux/io_uring
- @HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nlinux::io_uring \
- -t$(TESTCACHE)/linux/io_uring/linux_io_uring.td $(testlib_linux_io_uring_linux_srcs)
-
# linux::vdso (+linux)
testlib_linux_vdso_linux_srcs= \
$(STDLIB)/linux/vdso/vdso.ha