From: Pavel Begunkov <[email protected]>
To: [email protected]
Cc: Jens Axboe <[email protected]>, [email protected]
Subject: [PATCH liburing 3/4] test: test clockids and abs timeouts
Date: Sun, 18 Aug 2024 19:55:43 +0100 [thread overview]
Message-ID: <e5797a5e89c253045ae8f447275eec54dc6af722.1724007045.git.asml.silence@gmail.com> (raw)
In-Reply-To: <[email protected]>
Signed-off-by: Pavel Begunkov <[email protected]>
---
test/Makefile | 1 +
test/wait-timeout.c | 283 ++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 284 insertions(+)
create mode 100644 test/wait-timeout.c
diff --git a/test/Makefile b/test/Makefile
index 0538a75..f4fccd7 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -213,6 +213,7 @@ test_srcs := \
unlink.c \
version.c \
waitid.c \
+ wait-timeout.c \
wakeup-hang.c \
wq-aff.c \
xattr.c \
diff --git a/test/wait-timeout.c b/test/wait-timeout.c
new file mode 100644
index 0000000..1fc8e28
--- /dev/null
+++ b/test/wait-timeout.c
@@ -0,0 +1,283 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Description: run various timeout tests
+ *
+ */
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <assert.h>
+
+#include "helpers.h"
+#include "liburing.h"
+#include "../src/syscall.h"
+
+#define IO_NSEC_PER_SEC 1000000000LU
+
+static bool support_abs = false;
+static bool support_clock = false;
+
+static unsigned long long timespec_to_ns(struct timespec *ts)
+{
+ return ts->tv_nsec + ts->tv_sec * IO_NSEC_PER_SEC;
+}
+static struct timespec ns_to_timespec(unsigned long long t)
+{
+ struct timespec ts;
+
+ ts.tv_sec = t / IO_NSEC_PER_SEC;
+ ts.tv_nsec = t - ts.tv_sec * IO_NSEC_PER_SEC;
+ return ts;
+}
+
+static long long ns_since(struct timespec *ts)
+{
+ struct timespec now;
+ int ret;
+
+ ret = clock_gettime(CLOCK_MONOTONIC, &now);
+ if (ret) {
+ fprintf(stderr, "clock_gettime failed\n");
+ exit(T_EXIT_FAIL);
+ }
+
+ return timespec_to_ns(&now) - timespec_to_ns(ts);
+
+}
+
+static int t_io_uring_wait(struct io_uring *ring, int nr, unsigned enter_flags,
+ struct timespec *ts)
+{
+ struct io_uring_getevents_arg arg = {
+ .sigmask = 0,
+ .sigmask_sz = _NSIG / 8,
+ .ts = (unsigned long)ts
+ };
+ int ret;
+
+ enter_flags |= IORING_ENTER_GETEVENTS | IORING_ENTER_EXT_ARG;
+ ret = io_uring_enter2(ring->ring_fd, 0, nr, enter_flags,
+ (void *)&arg, sizeof(arg));
+ return ret;
+}
+
+static int probe_timers(void)
+{
+ struct io_uring_clock_register cr = { .clockid = CLOCK_MONOTONIC, };
+ struct io_uring ring;
+ struct timespec ts;
+ int ret;
+
+ ret = io_uring_queue_init(8, &ring, 0);
+ if (ret) {
+ fprintf(stderr, "probe ring setup failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = clock_gettime(CLOCK_MONOTONIC, &ts);
+ if (ret) {
+ fprintf(stderr, "clock_gettime failed\n");
+ return ret;
+ }
+
+ ret = t_io_uring_wait(&ring, 0, IORING_ENTER_ABS_TIMER, &ts);
+ if (!ret) {
+ support_abs = true;
+ } else if (ret != -EINVAL) {
+ fprintf(stderr, "wait failed %i\n", ret);
+ return ret;
+ }
+
+ ret = io_uring_register_clock(&ring, &cr);
+ if (!ret) {
+ support_clock = true;
+ } else if (ret != -EINVAL) {
+ fprintf(stderr, "io_uring_register_clock %i\n", ret);
+ return ret;
+ }
+
+ io_uring_queue_exit(&ring);
+ return 0;
+}
+
+static int test_timeout(bool abs, bool set_clock)
+{
+ unsigned enter_flags = abs ? IORING_ENTER_ABS_TIMER : 0;
+ struct io_uring ring;
+ struct timespec start, end, ts;
+ long long dt;
+ int ret;
+
+ ret = io_uring_queue_init(8, &ring, 0);
+ if (ret) {
+ fprintf(stderr, "ring setup failed: %d\n", ret);
+ return 1;
+ }
+
+ if (set_clock) {
+ struct io_uring_clock_register cr = {};
+
+ cr.clockid = CLOCK_BOOTTIME;
+ ret = io_uring_register_clock(&ring, &cr);
+ if (ret) {
+ fprintf(stderr, "io_uring_register_clock failed\n");
+ return 1;
+ }
+ }
+
+ /* pass current time */
+ ret = clock_gettime(CLOCK_MONOTONIC, &start);
+ assert(ret == 0);
+
+ ts = abs ? start : ns_to_timespec(0);
+ ret = t_io_uring_wait(&ring, 1, enter_flags, &ts);
+ if (ret != -ETIME) {
+ fprintf(stderr, "wait current time failed, %i\n", ret);
+ return 1;
+ }
+
+ if (ns_since(&start) >= IO_NSEC_PER_SEC) {
+ fprintf(stderr, "current time test failed\n");
+ return 1;
+ }
+
+ if (abs) {
+ /* expired time */
+ ret = clock_gettime(CLOCK_MONOTONIC, &start);
+ assert(ret == 0);
+ ts = ns_to_timespec(timespec_to_ns(&start) - IO_NSEC_PER_SEC);
+
+ ret = t_io_uring_wait(&ring, 1, enter_flags, &ts);
+ if (ret != -ETIME) {
+ fprintf(stderr, "expired timeout wait failed, %i\n", ret);
+ return 1;
+ }
+
+ ret = clock_gettime(CLOCK_MONOTONIC, &end);
+ assert(ret == 0);
+
+ if (ns_since(&start) >= IO_NSEC_PER_SEC) {
+ fprintf(stderr, "expired timer test failed\n");
+ return 1;
+ }
+ }
+
+ /* 1s wait */
+ ret = clock_gettime(CLOCK_MONOTONIC, &start);
+ assert(ret == 0);
+
+ dt = 2 * IO_NSEC_PER_SEC + (abs ? timespec_to_ns(&start) : 0);
+ ts = ns_to_timespec(dt);
+ ret = t_io_uring_wait(&ring, 1, enter_flags, &ts);
+ if (ret != -ETIME) {
+ fprintf(stderr, "wait timeout failed, %i\n", ret);
+ return 1;
+ }
+
+ dt = ns_since(&start);
+ if (dt < IO_NSEC_PER_SEC || dt > 3 * IO_NSEC_PER_SEC) {
+ fprintf(stderr, "early wake up, %lld\n", dt);
+ return 1;
+ }
+ return 0;
+}
+
+static int test_clock_setup(void)
+{
+ struct io_uring ring;
+ struct io_uring_clock_register cr = {};
+ int ret;
+
+ ret = io_uring_queue_init(8, &ring, 0);
+ if (ret) {
+ fprintf(stderr, "ring setup failed: %d\n", ret);
+ return T_EXIT_FAIL;
+ }
+
+ ret = __sys_io_uring_register(ring.ring_fd, IORING_REGISTER_CLOCK, NULL, 0);
+ if (!ret) {
+ fprintf(stderr, "invalid null clock registration %i\n", ret);
+ return T_EXIT_FAIL;
+ }
+
+ cr.clockid = -1;
+ ret = __sys_io_uring_register(ring.ring_fd, IORING_REGISTER_CLOCK, &cr, 0);
+ if (ret != -EINVAL) {
+ fprintf(stderr, "invalid clockid registration %i\n", ret);
+ return T_EXIT_FAIL;
+ }
+
+ cr.clockid = CLOCK_MONOTONIC;
+ ret = __sys_io_uring_register(ring.ring_fd, IORING_REGISTER_CLOCK, &cr, 0);
+ if (ret) {
+ fprintf(stderr, "clock monotonic registration failed %i\n", ret);
+ return T_EXIT_FAIL;
+ }
+
+ cr.clockid = CLOCK_BOOTTIME;
+ ret = __sys_io_uring_register(ring.ring_fd, IORING_REGISTER_CLOCK, &cr, 0);
+ if (ret) {
+ fprintf(stderr, "clock boottime registration failed %i\n", ret);
+ return T_EXIT_FAIL;
+ }
+
+ cr.clockid = CLOCK_MONOTONIC;
+ ret = __sys_io_uring_register(ring.ring_fd, IORING_REGISTER_CLOCK, &cr, 0);
+ if (ret) {
+ fprintf(stderr, "2nd clock monotonic registration failed %i\n", ret);
+ return T_EXIT_FAIL;
+ }
+
+ io_uring_queue_exit(&ring);
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ int ret, i;
+
+ if (argc > 1)
+ return 0;
+
+ ret = probe_timers();
+ if (ret) {
+ fprintf(stderr, "probe failed\n");
+ return T_EXIT_FAIL;
+ }
+ if (!support_abs && !support_clock)
+ return T_EXIT_SKIP;
+
+ if (support_clock) {
+ ret = test_clock_setup();
+ if (ret) {
+ fprintf(stderr, "test_clock_setup failed\n");
+ return T_EXIT_FAIL;
+ }
+ }
+
+ for (i = 0; i < 4; i++) {
+ bool abs = i & 1;
+ bool clock = i & 2;
+
+ if (abs && !support_abs)
+ continue;
+ if (clock && !support_clock)
+ continue;
+
+ ret = test_timeout(abs, clock);
+ if (ret) {
+ fprintf(stderr, "test_timeout failed %i %i\n",
+ abs, clock);
+ return ret;
+ }
+ }
+
+ return 0;
+}
--
2.45.2
next prev parent reply other threads:[~2024-08-18 18:55 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-08-18 18:55 [PATCH liburing 0/4] Tests for absolute timeouts and clockids Pavel Begunkov
2024-08-18 18:55 ` [PATCH liburing 1/4] Sync kernel headers Pavel Begunkov
2024-08-18 18:55 ` [PATCH liburing 2/4] src/register: add clock id registration helper Pavel Begunkov
2024-08-18 18:55 ` Pavel Begunkov [this message]
2024-08-18 18:55 ` [PATCH liburing 4/4] man: document clock id and IORING_ENTER_ABS_TIMER Pavel Begunkov
2024-08-18 19:39 ` [PATCH liburing 0/4] Tests for absolute timeouts and clockids Jens Axboe
2024-08-18 19:40 ` Jens Axboe
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=e5797a5e89c253045ae8f447275eec54dc6af722.1724007045.git.asml.silence@gmail.com \
[email protected] \
[email protected] \
[email protected] \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox