Skip to content

Commit

Permalink
examples/reg-wait: add registered wait example
Browse files Browse the repository at this point in the history
Sometimes a bit of code is more useful than a man page. Add a basic
example of how to use registered waits, using two indices. One is
just a basic timeout wait, the other one uses min_wait_usec as well.

Signed-off-by: Jens Axboe <[email protected]>
  • Loading branch information
axboe committed Nov 2, 2024
1 parent e065fb8 commit abe992c
Show file tree
Hide file tree
Showing 2 changed files with 140 additions and 0 deletions.
1 change: 1 addition & 0 deletions examples/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ example_srcs := \
napi-busy-poll-client.c \
napi-busy-poll-server.c \
poll-bench.c \
reg-wait.c \
send-zerocopy.c \
rsrc-update-bench.c \
proxy.c \
Expand Down
139 changes: 139 additions & 0 deletions examples/reg-wait.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
/* SPDX-License-Identifier: MIT */
/*
* Sample program that shows how to use registered waits.
*
* (C) 2024 Jens Axboe <[email protected]>
*/
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
#include <liburing.h>

static unsigned long long mtime_since(const struct timeval *s, const struct timeval *e)
{
long long sec, usec;

sec = e->tv_sec - s->tv_sec;
usec = (e->tv_usec - s->tv_usec);
if (sec > 0 && usec < 0) {
sec--;
usec += 1000000;
}

sec *= 1000;
usec /= 1000;
return sec + usec;
}

static unsigned long long mtime_since_now(struct timeval *tv)
{
struct timeval end;

gettimeofday(&end, NULL);
return mtime_since(tv, &end);
}

int main(int argc, char *argv[])
{
struct io_uring_reg_wait *reg;
struct io_uring_sqe *sqe;
struct io_uring_cqe *cqe[2];
struct io_uring ring;
char b1[8], b2[8];
unsigned long msec;
struct timeval tv;
int ret, fds[2];

if (pipe(fds) < 0) {
perror("pipe");
return 1;
}

ret = io_uring_queue_init(8, &ring, 0);
if (ret) {
fprintf(stderr, "Queue init: %d\n", ret);
return 1;
}

/*
* Setup wait region. We'll use 32 here, but 64 is probably a more
* logical value, as it'll pin a page regardless of size. 64 is the
* max value on a 4k page size architecture.
*/
reg = io_uring_setup_reg_wait(&ring, 32, &ret);
if (!reg) {
if (ret == -EINVAL) {
fprintf(stderr, "Kernel doesn't support registered waits\n");
return 1;
}
fprintf(stderr, "Registered wait: %d\n", ret);
return 1;
}

/*
* Setup two distinct wait regions. Index 0 will be a 1 second wait,
* and region 2 is a short wait using min_wait_usec as well. Neither
* of these use a signal mask, but sigmask/sigmask_sz can be set as
* well for that.
*/
reg[0].ts.tv_sec = 1;
reg[0].ts.tv_nsec = 0;
reg[0].flags = IORING_REG_WAIT_TS;

reg[1].ts.tv_sec = 0;
reg[1].ts.tv_nsec = 100000000LL;
reg[1].min_wait_usec = 10000;
reg[1].flags = IORING_REG_WAIT_TS;

/*
* No pending completions. Wait with region 0, which should time
* out after 1 second.
*/
gettimeofday(&tv, NULL);
ret = io_uring_submit_and_wait_reg(&ring, cqe, 1, 0);
if (ret == -EINVAL) {
fprintf(stderr, "Kernel doesn't support registered waits\n");
return 1;
} else if (ret != -ETIME) {
fprintf(stderr, "Wait should've timed out... %d\n", ret);
return 1;
}
msec = mtime_since_now(&tv);
if (msec < 900 || msec > 1100) {
fprintf(stderr, "Wait took an unexpected amount of time: %lu\n",
msec);
return 1;
}

/*
* Now prepare two pipe reads. We'll trigger one completion quickly,
* but the other one will never happen. Use min_wait_usec timeout
* to abort after 10 msec of time, where the overall timeout is
* otherwise 100 msec. Since we're waiting on two events, the min
* timeout ends up aborting us.
*/
sqe = io_uring_get_sqe(&ring);
io_uring_prep_read(sqe, fds[0], b1, sizeof(b1), 0);
sqe = io_uring_get_sqe(&ring);
io_uring_prep_read(sqe, fds[0], b2, sizeof(b2), 0);

/* trigger one read */
write(fds[1], "Hello", 5);

gettimeofday(&tv, NULL);
ret = io_uring_submit_and_wait_reg(&ring, cqe, 2, 1);
msec = mtime_since_now(&tv);
if (ret != 2) {
fprintf(stderr, "Should have submitted 2: %d\n", ret);
return 1;
}
if (msec < 8 || msec > 12) {
fprintf(stderr, "min_wait_usec should take ~10 msec: %lu\n", msec);
return 1;
}

return 0;
}

0 comments on commit abe992c

Please sign in to comment.