diff --git a/test/timeout.c b/test/timeout.c index e656ad470..ff444784e 100644 --- a/test/timeout.c +++ b/test/timeout.c @@ -1063,6 +1063,150 @@ static int test_update_timeout(struct io_uring *ring, unsigned long ms, return 1; } +static int test_update_multishot_timeouts(struct io_uring *ring, unsigned long ms) +{ + struct io_uring_sqe *sqe; + struct io_uring_cqe *cqe; + struct __kernel_timespec ts, ts_upd; + unsigned long long exp_ms, base_ms = 10000; + struct timeval tv1, tv2; + int ret, i, nr = 6; + __u32 mode = 0; + + msec_to_ts(&ts, base_ms); + + msec_to_ts(&ts_upd, ms); + gettimeofday(&tv1, NULL); + gettimeofday(&tv2, NULL); + + sqe = io_uring_get_sqe(ring); + if (!sqe) { + fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__); + goto err; + } + + msec_to_ts(&ts, base_ms); + io_uring_prep_timeout(sqe, &ts, 0, IORING_TIMEOUT_MULTISHOT); + sqe->user_data = 1; + + sqe = io_uring_get_sqe(ring); + if (!sqe) { + fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__); + goto err; + } + + io_uring_prep_timeout(sqe, &ts, 0, IORING_TIMEOUT_MULTISHOT); + sqe->user_data = 2; + + sqe = io_uring_get_sqe(ring); + if (!sqe) { + fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__); + goto err; + } + + io_uring_prep_timeout_update(sqe, &ts_upd, 1, mode); + sqe->user_data = 3; + + sqe = io_uring_get_sqe(ring); + if (!sqe) { + fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__); + goto err; + } + + io_uring_prep_timeout_update(sqe, &ts_upd, 2, mode); + sqe->user_data = 4; + + ret = io_uring_submit(ring); + if (ret == 0) { + fprintf(stderr, "%s: sqe submit failed: %d\n", __FUNCTION__, ret); + goto err; + } + + for (i = 0; i < nr; i++) { + ret = io_uring_wait_cqe(ring, &cqe); + if (ret < 0) { + fprintf(stderr, "%s: wait completion %d\n", __FUNCTION__, ret); + goto err; + } + + switch (cqe->user_data) { + case 1: + if (cqe->res != -ETIME) { + fprintf(stderr, "%s: got %d, wanted %d\n", + __FUNCTION__, cqe->res, -ETIME); + goto err; + } + exp_ms = mtime_since_now(&tv1); + if (exp_ms > 1.05 * ms) { + fprintf(stderr, "too long, timeout wasn't updated (expired after %llu instead of %lu)\n", exp_ms, ms); + goto err; + } + gettimeofday(&tv1, NULL); + + break; + case 2: + if (cqe->res != -ETIME) { + fprintf(stderr, "%s: got %d, wanted %d\n", + __FUNCTION__, cqe->res, -ETIME); + goto err; + } + exp_ms = mtime_since_now(&tv2); + if (exp_ms > 1.05 * ms) { + fprintf(stderr, "too long, timeout wasn't updated (expired after %llu instead of %lu)\n", exp_ms, ms); + goto err; + } + gettimeofday(&tv2, NULL); + break; + case 3: + case 4: + if (cqe->res != 0) { + fprintf(stderr, "%s: got %d, wanted %d\n", + __FUNCTION__, cqe->res, 0); + goto err; + } + break; + default: + goto err; + } + io_uring_cqe_seen(ring, cqe); + } + + sqe = io_uring_get_sqe(ring); + if (!sqe) { + fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__); + goto err; + } + + io_uring_prep_timeout_remove(sqe, 1, 0); + + sqe = io_uring_get_sqe(ring); + if (!sqe) { + fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__); + goto err; + } + + io_uring_prep_timeout_remove(sqe, 2, 0); + + ret = io_uring_submit(ring); + if (ret != 2) { + fprintf(stderr, "%s: sqe submit failed: %d\n", __FUNCTION__, ret); + goto err; + } + + for (i = 0; i < 2; i++) { + ret = io_uring_wait_cqe(ring, &cqe); + if (ret < 0) { + fprintf(stderr, "%s: wait completion %d\n", __FUNCTION__, ret); + goto err; + } + io_uring_cqe_seen(ring, cqe); + } + + return 0; +err: + return 1; +} + static int test_update_nonexistent_timeout(struct io_uring *ring) { struct io_uring_sqe *sqe; @@ -1790,6 +1934,12 @@ int main(int argc, char *argv[]) return ret; } + ret = test_update_multishot_timeouts(&ring, 200); + if (ret) { + fprintf(stderr, "test_update_multishot_timeouts linked failed\n"); + return ret; + } + if (sqpoll) { ret = test_update_timeout(&sqpoll_ring, 0, false, false, false);