Merge branch 'submit-and-wait-ts'

Merge in branch fixing up io_uring_submit_and_wait_timeout().

* submit-and-wait-ts:
  man: io_uring_submit_and_wait(_timeout) updates
  Add io_uring_submit_and_wait_timeout() test
  Revert "man/io_uring_submit_and_wait_timeout.3: fix return value description"
  src/queue: don't wait twice if looping in _io_uring_get_cqe()
  test/recv-multishot.c: check for error specifically when submitting
This commit is contained in:
Jens Axboe
2022-10-22 15:13:19 -06:00
6 changed files with 140 additions and 15 deletions
+1 -1
View File
@@ -16,7 +16,7 @@ io_uring_submit_and_wait \- submit requests to the submission queue and wait for
.PP
The
.BR io_uring_submit_and_wait (3)
function submits the next events to the submission queue belonging to the
function submits the next requests from the submission queue belonging to the
.I ring
and waits for
.I wait_nr
+5 -7
View File
@@ -20,11 +20,11 @@ wait for the completion with timeout
.PP
The
.BR io_uring_submit_and_wait_timeout (3)
function submits the next events to the submission queue belonging to the
function submits the next requests from the submission queue belonging to the
.I ring
and waits for
.I wait_nr
completion events or until the timeout
completion events, or until the timeout
.I ts
expires. The completion events are stored in the
.I cqe_ptr
@@ -38,15 +38,13 @@ After the caller retrieves a submission queue entry (SQE) with
and prepares the SQE, it can be submitted with
.BR io_uring_submit_and_wait_timeout (3) .
Unlike the other submit functions, this does not return the number of submitted entries.
The actual number submitted can be less than the total number of ready SQEs if there
was an error submitting an SQE. It is not an error to submit less than the total number of SQEs.
.SH RETURN VALUE
On success
.BR io_uring_submit_and_wait_timeout (3)
returns 0 and the cqe_ptr param is filled in. On failure it returns
returns the number of submitted submission queue entries. On failure it returns
.BR -errno .
Note that in earlier versions of the liburing library, the return value was 0
on success.
The most common failure case is not receiving a completion within the specified
timeout,
.B -ETIME
+24 -6
View File
@@ -55,6 +55,7 @@ struct get_data {
unsigned wait_nr;
unsigned get_flags;
int sz;
int has_ts;
void *arg;
};
@@ -64,7 +65,7 @@ static int _io_uring_get_cqe(struct io_uring *ring,
{
struct io_uring_cqe *cqe = NULL;
bool looped = false;
int err;
int err = 0;
do {
bool need_enter = false;
@@ -72,9 +73,12 @@ static int _io_uring_get_cqe(struct io_uring *ring,
unsigned nr_available;
int ret;
err = __io_uring_peek_cqe(ring, &cqe, &nr_available);
if (err)
ret = __io_uring_peek_cqe(ring, &cqe, &nr_available);
if (ret) {
if (!err)
err = ret;
break;
}
if (!cqe && !data->wait_nr && !data->submit) {
/*
* If we already looped once, we already entererd
@@ -82,7 +86,8 @@ static int _io_uring_get_cqe(struct io_uring *ring,
* wait for, don't keep retrying.
*/
if (looped || !cq_ring_needs_enter(ring)) {
err = -EAGAIN;
if (!err)
err = -EAGAIN;
break;
}
need_enter = true;
@@ -95,6 +100,13 @@ static int _io_uring_get_cqe(struct io_uring *ring,
need_enter = true;
if (!need_enter)
break;
if (looped && data->has_ts) {
struct io_uring_getevents_arg *arg = data->arg;
if (!cqe && arg->ts && !err)
err = -ETIME;
break;
}
if (ring->int_flags & INT_FLAG_REG_RING)
flags |= IORING_ENTER_REGISTERED_RING;
@@ -102,14 +114,18 @@ static int _io_uring_get_cqe(struct io_uring *ring,
data->wait_nr, flags, data->arg,
data->sz);
if (ret < 0) {
err = ret;
if (!err)
err = ret;
break;
}
data->submit -= ret;
if (cqe)
break;
looped = true;
if (!looped) {
looped = true;
err = ret;
}
} while (1);
*cqe_ptr = cqe;
@@ -233,6 +249,7 @@ static int io_uring_wait_cqes_new(struct io_uring *ring,
.wait_nr = wait_nr,
.get_flags = IORING_ENTER_EXT_ARG,
.sz = sizeof(arg),
.has_ts = ts != NULL,
.arg = &arg
};
@@ -317,6 +334,7 @@ int io_uring_submit_and_wait_timeout(struct io_uring *ring,
.wait_nr = wait_nr,
.get_flags = IORING_ENTER_EXT_ARG,
.sz = sizeof(arg),
.has_ts = ts != NULL,
.arg = &arg
};
+1
View File
@@ -163,6 +163,7 @@ test_srcs := \
sqpoll-sleep.c \
sq-space_left.c \
stdout.c \
submit-and-wait.c \
submit-link-fail.c \
submit-reuse.c \
sync-cancel.c \
+1 -1
View File
@@ -141,7 +141,7 @@ static int test(struct args *args)
buffer_size, 1, 7, i);
io_uring_sqe_set_data64(sqe, 0x999);
memset(recv_buffs[i], 0xcc, buffer_size);
if (io_uring_submit_and_wait_timeout(&ring, &cqe, 1, &timeout, NULL) != 0) {
if (io_uring_submit_and_wait_timeout(&ring, &cqe, 1, &timeout, NULL) < 0) {
fprintf(stderr, "provide buffers failed: %d\n", ret);
ret = -1;
goto cleanup;
+108
View File
@@ -0,0 +1,108 @@
/* SPDX-License-Identifier: MIT */
/*
* Description: Test that io_uring_submit_and_wait_timeout() returns the
* right value (submit count) and that it doesn't end up waiting twice.
*
*/
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/time.h>
#include "liburing.h"
#include "test.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);
}
static int test(struct io_uring *ring)
{
struct io_uring_cqe *cqe;
struct io_uring_sqe *sqe;
struct __kernel_timespec ts;
struct timeval tv;
int ret, i;
for (i = 0; i < 1; i++) {
sqe = io_uring_get_sqe(ring);
if (!sqe) {
fprintf(stderr, "get sqe failed at %d\n", i);
goto err;
}
io_uring_prep_nop(sqe);
}
ts.tv_sec = 1;
ts.tv_nsec = 0;
gettimeofday(&tv, NULL);
ret = io_uring_submit_and_wait_timeout(ring, &cqe, 2, &ts, NULL);
if (ret < 0) {
fprintf(stderr, "submit_and_wait_timeout: %d\n", ret);
goto err;
}
ret = mtime_since_now(&tv);
/* allow some slack, should be around 1s */
if (ret > 1200) {
fprintf(stderr, "wait took too long: %d\n", ret);
goto err;
}
return 0;
err:
return 1;
}
static int test_ring(void)
{
struct io_uring ring;
struct io_uring_params p = { };
int ret;
p.flags = 0;
ret = io_uring_queue_init_params(8, &ring, &p);
if (ret) {
fprintf(stderr, "ring setup failed: %d\n", ret);
return 1;
}
ret = test(&ring);
if (ret) {
fprintf(stderr, "test failed\n");
goto err;
}
err:
io_uring_queue_exit(&ring);
return ret;
}
int main(int argc, char *argv[])
{
if (argc > 1)
return 0;
return test_ring();
}