~sircmpwn/hare unlisted

ad0e2cef986d0df1ce241945147b846deb11f349 — Drew DeVault a month ago d9489a8
linux::io_uring: implement io_uring_register
A linux/io_uring/register.ha => linux/io_uring/register.ha +144 -0
@@ 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,
	};
};

M linux/io_uring/sqe.ha => linux/io_uring/sqe.ha +0 -2
@@ 1,5 1,3 @@
// TODO:
// - Interface for buffer registration
use rt;
use types;


M linux/io_uring/uring.ha => linux/io_uring/uring.ha +5 -5
@@ 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

M rt/+linux/syscalls.ha => rt/+linux/syscalls.ha +2 -5
@@ 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,

M scripts/gen-stdlib => scripts/gen-stdlib +1 -0
@@ 520,6 520,7 @@ linux() {
linux_io_uring() {
	gen_srcs linux::io_uring \
		queue.ha \
		register.ha \
		setup.ha \
		sqe.ha \
		uring.ha

M stdlib.mk => stdlib.mk +2 -0
@@ 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