From a2a652e521c12c28a0cc7b397216b78804b1142a Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Wed, 19 May 2021 15:37:56 -0400 Subject: [PATCH] linux::io_uring: timeout operations Signed-off-by: Drew DeVault --- io_uring/cqe.ha | 12 ++++++++++-- io_uring/sqe.ha | 46 +++++++++++++++++++++++++++++++++++++++++++++- io_uring/uring.ha | 8 +++++++- diff --git a/io_uring/cqe.ha b/io_uring/cqe.ha index 9705b4ba94ba6b4da50fe33bd1318d8b0eab81e8..0f5b7d5df6fe93aaa0cb611f2e4d3c8f8e059eba 100644 --- a/io_uring/cqe.ha +++ b/io_uring/cqe.ha @@ -28,8 +28,16 @@ // 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; +export fn result(cqe: *cqe) (int | error) = { + // TODO: Flesh out more errors + return if (cqe.res < 0) switch (-cqe.res) { + rt::ETIME => errors::timeout, + rt::ECANCELED => errors::cancelled, + * => errors::errno(rt::wrap_errno(-cqe.res)), + } else { + cqe.res; + }; +}; // Gets the user data field of a [[cqe]]. See [[set_user]] for the corresponding // SQE function. diff --git a/io_uring/sqe.ha b/io_uring/sqe.ha index 6d47f8c5291ed49e0a155cb42724a3b2843364a7..975f71e49db23dd77ae09f1e6cca46ae62207b2f 100644 --- a/io_uring/sqe.ha +++ b/io_uring/sqe.ha @@ -148,7 +148,8 @@ 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. +// Removes an existing poll request by matching the SQE's user_data field. See +// [[setuser]]. export fn poll_remove(sqe: *sqe, user_data: *void, flags: sqe_flags...) void = { preprw(sqe, op::POLL_REMOVE, -1, null, 0, 0, flags...); set_user(sqe, user_data); @@ -209,3 +210,46 @@ 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 [[setuser]] 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: sqe_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 [[setuser]]. +export fn timeout_remove( + sqe: *sqe, + user_data: *void, + to_flags: timeout_flags, + flags: sqe_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 [[setuser]]. +export fn timeout_update( + sqe: *sqe, + user_data: *void, + ts: *rt::timespec, + events: uint, + to_flags: timeout_flags, + flags: sqe_flags... +) void = { + preprw(sqe, op::TIMEOUT_REMOVE, 0, user_data, 0, events, flags...); + sqe.timeout_flags = to_flags | timeout_flags::UPDATE; + sqe.addr2 = ts; +}; diff --git a/io_uring/uring.ha b/io_uring/uring.ha index e6e7441f3cbd4dea81ac27fe91f7c825fe954df8..fec9360cd4afb006f9670b13d4c09ef926d02584 100644 --- a/io_uring/uring.ha +++ b/io_uring/uring.ha @@ -1,7 +1,7 @@ use errors; // All errors which may be returned by this module. -export type error = errors::opaque; +export type error = (errors::timeout | errors::cancelled | errors::opaque); // Converts an [[error]] into a human-readable string. export fn strerror(err: error) const str = { @@ -77,7 +77,13 @@ }; // Flags for a timeout operation. export type timeout_flags = enum u32 { + // 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. -- 2.48.1