diff options
author | ilnaz <ilnaz@ydb.tech> | 2022-12-13 16:01:38 +0300 |
---|---|---|
committer | ilnaz <ilnaz@ydb.tech> | 2022-12-13 16:01:38 +0300 |
commit | f2bea70bea01921ec43846224d100f2c70dd5719 (patch) | |
tree | eead917572063b63adc1c9a76284c8fbd10f25a3 /contrib/libs/liburing/test/timeout-overflow.c | |
parent | 1ab9ee3dfe0ab4023a3a57bf55de31dff3eac908 (diff) | |
download | ydb-f2bea70bea01921ec43846224d100f2c70dd5719.tar.gz |
Add cross-link
Diffstat (limited to 'contrib/libs/liburing/test/timeout-overflow.c')
-rw-r--r-- | contrib/libs/liburing/test/timeout-overflow.c | 205 |
1 files changed, 205 insertions, 0 deletions
diff --git a/contrib/libs/liburing/test/timeout-overflow.c b/contrib/libs/liburing/test/timeout-overflow.c new file mode 100644 index 0000000000..8c57ff31b1 --- /dev/null +++ b/contrib/libs/liburing/test/timeout-overflow.c @@ -0,0 +1,205 @@ +#include "../config-host.h" +/* SPDX-License-Identifier: MIT */ +/* + * Description: run timeout overflow test + * + */ +#include <errno.h> +#include <stdio.h> +#include <limits.h> +#include <string.h> +#include <sys/time.h> + +#include "liburing.h" +#include "helpers.h" + +#define TIMEOUT_MSEC 200 +static int not_supported; + +static void msec_to_ts(struct __kernel_timespec *ts, unsigned int msec) +{ + ts->tv_sec = msec / 1000; + ts->tv_nsec = (msec % 1000) * 1000000; +} + +static int check_timeout_support(void) +{ + struct io_uring_sqe *sqe; + struct io_uring_cqe *cqe; + struct __kernel_timespec ts; + struct io_uring_params p; + struct io_uring ring; + int ret; + + memset(&p, 0, sizeof(p)); + ret = io_uring_queue_init_params(1, &ring, &p); + if (ret) { + fprintf(stderr, "ring setup failed: %d\n", ret); + return T_EXIT_FAIL; + } + + /* not really a match, but same kernel added batched completions */ + if (p.features & IORING_FEAT_POLL_32BITS) { + not_supported = 1; + return T_EXIT_SKIP; + } + + sqe = io_uring_get_sqe(&ring); + msec_to_ts(&ts, TIMEOUT_MSEC); + io_uring_prep_timeout(sqe, &ts, 1, 0); + + ret = io_uring_submit(&ring); + if (ret < 0) { + fprintf(stderr, "sqe submit failed: %d\n", ret); + goto err; + } + + ret = io_uring_wait_cqe(&ring, &cqe); + if (ret < 0) { + fprintf(stderr, "wait completion %d\n", ret); + goto err; + } + + if (cqe->res == -EINVAL) { + not_supported = 1; + fprintf(stdout, "Timeout not supported, ignored\n"); + return 0; + } + + io_uring_cqe_seen(&ring, cqe); + io_uring_queue_exit(&ring); + return T_EXIT_PASS; +err: + io_uring_queue_exit(&ring); + return T_EXIT_FAIL; +} + +/* + * We first setup 4 timeout requests, which require a count value of 1, 1, 2, + * UINT_MAX, so the sequence is 1, 2, 4, 2. Before really timeout, this 4 + * requests will not lead the change of cq_cached_tail, so as sq_dropped. + * + * And before this patch. The order of this four requests will be req1->req2-> + * req4->req3. Actually, it should be req1->req2->req3->req4. + * + * Then, if there is 2 nop req. All timeout requests expect req4 will completed + * successful after the patch. And req1/req2 will completed successful with + * req3/req4 return -ETIME without this patch! + */ +static int test_timeout_overflow(void) +{ + struct io_uring_sqe *sqe; + struct io_uring_cqe *cqe; + struct __kernel_timespec ts; + struct io_uring ring; + int i, ret; + + ret = io_uring_queue_init(16, &ring, 0); + if (ret) { + fprintf(stderr, "ring setup failed: %d\n", ret); + return 1; + } + + msec_to_ts(&ts, TIMEOUT_MSEC); + for (i = 0; i < 4; i++) { + unsigned num = 0; + sqe = io_uring_get_sqe(&ring); + switch (i) { + case 0: + case 1: + num = 1; + break; + case 2: + num = 2; + break; + case 3: + num = UINT_MAX; + break; + } + io_uring_prep_timeout(sqe, &ts, num, 0); + } + + for (i = 0; i < 2; i++) { + sqe = io_uring_get_sqe(&ring); + io_uring_prep_nop(sqe); + io_uring_sqe_set_data(sqe, (void *) 1); + } + ret = io_uring_submit(&ring); + if (ret < 0) { + fprintf(stderr, "sqe submit failed: %d\n", ret); + goto err; + } + + i = 0; + while (i < 6) { + ret = io_uring_wait_cqe(&ring, &cqe); + if (ret < 0) { + fprintf(stderr, "wait completion %d\n", ret); + goto err; + } + + /* + * cqe1: first nop req + * cqe2: first timeout req, because of cqe1 + * cqe3: second timeout req because of cqe1 + cqe2 + * cqe4: second nop req + * cqe5~cqe6: the left three timeout req + */ + switch (i) { + case 0: + case 3: + if (io_uring_cqe_get_data(cqe) != (void *) 1) { + fprintf(stderr, "nop not seen as 1 or 2\n"); + goto err; + } + break; + case 1: + case 2: + case 4: + if (cqe->res == -ETIME) { + fprintf(stderr, "expected not return -ETIME " + "for the #%d timeout req\n", i - 1); + goto err; + } + break; + case 5: + if (cqe->res != -ETIME) { + fprintf(stderr, "expected return -ETIME for " + "the #%d timeout req\n", i - 1); + goto err; + } + break; + } + io_uring_cqe_seen(&ring, cqe); + i++; + } + + return 0; +err: + return 1; +} + +int main(int argc, char *argv[]) +{ + int ret; + + if (argc > 1) + return T_EXIT_SKIP; + + ret = check_timeout_support(); + if (ret == T_EXIT_FAIL) { + fprintf(stderr, "check_timeout_support failed: %d\n", ret); + return T_EXIT_FAIL; + } + + if (not_supported) + return T_EXIT_SKIP; + + ret = test_timeout_overflow(); + if (ret) { + fprintf(stderr, "test_timeout_overflow failed\n"); + return T_EXIT_FAIL; + } + + return T_EXIT_PASS; +} |