hare

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

commit ad0e2cef986d0df1ce241945147b846deb11f349
parent d9489a887724bc0a012c7764e05039ec576c87e8
Author: Drew DeVault <sir@cmpwn.com>
Date:   Mon, 17 May 2021 16:06:31 -0400

linux::io_uring: implement io_uring_register

Diffstat:
Alinux/io_uring/register.ha | 144+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mlinux/io_uring/sqe.ha | 2--
Mlinux/io_uring/uring.ha | 10+++++-----
Mrt/+linux/syscalls.ha | 7++-----
Mscripts/gen-stdlib | 1+
Mstdlib.mk | 2++
6 files changed, 154 insertions(+), 12 deletions(-)

diff --git a/linux/io_uring/register.ha b/linux/io_uring/register.ha @@ -0,0 +1,144 @@ +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). +export fn register_buffers(ring: *io_uring, iov: []rt::iovec) (void | error) = { + assert(len(iov) <= types::UINT_MAX); + return match (rt::io_uring_register(ring.fd, regop::REGISTER_BUFFERS, + iov: *[*]rt::iovec, len(iov): uint)) { + err: rt::errno => errors::errno(err), + int => void, + }; +}; + +// Unregisters all fixed buffers associated with an [[io_uring]]. +export fn unregister_buffers(ring: *io_uring) (void | error) = { + return match (rt::io_uring_register(ring.fd, + regop::UNREGISTER_BUFFERS, null, 0)) { + err: rt::errno => errors::errno(err), + 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); + return match (rt::io_uring_register(ring.fd, regop::REGISTER_FILES, + files: *[*]int, len(files): uint)) { + err: rt::errno => errors::errno(err), + 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); + return match (rt::io_uring_register(ring.fd, regop::REGISTER_FILES_UPDATE, + updates: *[*]files_update, len(updates): uint)) { + err: rt::errno => errors::errno(err), + int => void, + }; +}; + +// Unregisters all files associated with an [[io_uring]]. +export fn unregister_files(ring: *io_uring) (void | error) = { + return match (rt::io_uring_register(ring.fd, + regop::UNREGISTER_FILES, null, 0)) { + err: rt::errno => errors::errno(err), + 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) = { + return match (rt::io_uring_register(ring.fd, + regop::REGISTER_EVENTFD, &fd, 1)) { + err: rt::errno => errors::errno(err), + 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) = { + return match (rt::io_uring_register(ring.fd, + regop::REGISTER_EVENTFD_ASYNC, &fd, 1)) { + err: rt::errno => errors::errno(err), + int => void, + }; +}; + +// Unregisters the eventfd(2) associated with this [[io_uring]]. +export fn unregister_eventfd(ring: *io_uring) (void | error) = { + return match (rt::io_uring_register(ring.fd, + regop::UNREGISTER_EVENTFD, null, 0)) { + err: rt::errno => errors::errno(err), + 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 = { + return match (rt::io_uring_register(ring.fd, + regop::REGISTER_PERSONALITY, null, 0)) { + rt::errno => abort("Unexpected io_uring REGISTER_PERSONALITY error"), + i: int => i, + }; +}; + +// Unregisters a personality previously configured with +// [[register_personality]]. +export fn unregister_personality(ring: *io_uring, id: int) (void | error) = { + return match (rt::io_uring_register(ring.fd, + regop::UNREGISTER_PERSONALITY, null, id: uint)) { + err: rt::errno => errors::errno(err), + 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) = { + return match (rt::io_uring_register(ring.fd, + regop::REGISTER_ENABLE_RINGS, null, 0)) { + err: rt::errno => errors::errno(err), + 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); + return match (rt::io_uring_register(ring.fd, regop::REGISTER_RESTRICTIONS, + res: *[*]restriction, len(res): uint)) { + err: rt::errno => errors::errno(err), + int => void, + }; +}; diff --git a/linux/io_uring/sqe.ha b/linux/io_uring/sqe.ha @@ -1,5 +1,3 @@ -// TODO: -// - Interface for buffer registration use rt; use types; diff --git a/linux/io_uring/uring.ha b/linux/io_uring/uring.ha @@ -276,18 +276,18 @@ export type probe = struct { // Details for a REGISTER_RESTRICTIONS operation. export type restriction = struct { - opcode: restriction_op, + opcode: resop, union { - register_op: u8, - sqe_op: u8, - sqe_flags: u8, + register_op: regop, + sqe_op: op, + sqe_flags: sqe_flags, }, resv: u8, resv2: [3]u32, }; // Opcode for a [[restriction]]. -export type restriction_op = enum u16 { +export type resop = enum u16 { // Allow an io_uring_register(2) opcode REGISTER_OP = 0, // Allow an sqe opcode diff --git a/rt/+linux/syscalls.ha b/rt/+linux/syscalls.ha @@ -608,11 +608,8 @@ export fn io_uring_register( opcode: uint, arg: nullable *void, nr_args: uint, -) (void | errno) = { - wrap_return(syscall4(SYS_io_uring_register, - fd: u64, opcode: u64, arg: uintptr: u64, nr_args: u64))?; - return; -}; +) (int | errno) = wrap_return(syscall4(SYS_io_uring_register, + fd: u64, opcode: u64, arg: uintptr: u64, nr_args: u64))?: int; export fn io_uring_enter( fd: int, diff --git a/scripts/gen-stdlib b/scripts/gen-stdlib @@ -520,6 +520,7 @@ linux() { linux_io_uring() { gen_srcs linux::io_uring \ queue.ha \ + register.ha \ setup.ha \ sqe.ha \ uring.ha diff --git a/stdlib.mk b/stdlib.mk @@ -759,6 +759,7 @@ $(HARECACHE)/linux/linux.ssa: $(stdlib_linux_srcs) $(stdlib_rt) $(stdlib_format_ # linux::io_uring stdlib_linux_io_uring_srcs= \ $(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 @@ -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/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