test/iopoll: add explicit test case for io_uring_peek_cqe() and IOPOLL
If we're using IOPOLL, then we always need to enter the kernel for a peek
operation. This used to be an issue with liburing, but does work fine
now. Let's ensure it keeps working.
@@ -201,6 +201,77 @@ err:
return 1;
}
+static void sig_alrm(int sig)
+{
+ fprintf(stderr, "Ran out of time for peek test!\n");
+ exit(T_EXIT_FAIL);
+}
+
+/*
+ * if we are polling, io_uring_cqe_peek() always needs to enter the kernel
+ */
+static int test_io_uring_cqe_peek(const char *file)
+{
+ struct io_uring_cqe *cqe;
+ struct io_uring ring;
+ struct sigaction act;
+ int fd, i, ret = T_EXIT_FAIL;
+
+ if (no_iopoll)
+ return 0;
+
+ ret = io_uring_queue_init(64, &ring, IORING_SETUP_IOPOLL);
+ if (ret) {
+ fprintf(stderr, "ring create failed: %d\n", ret);
+ return 1;
+ }
+
+ fd = open(file, O_RDONLY | O_DIRECT);
+ if (fd < 0) {
+ perror("file open");
+ goto err;
+ }
+
+ for (i = 0; i < BUFFERS; i++) {
+ struct io_uring_sqe *sqe;
+ off_t offset = BS * (rand() % BUFFERS);
+
+ sqe = io_uring_get_sqe(&ring);
+ io_uring_prep_readv(sqe, fd, &vecs[i], 1, offset);
+ sqe->user_data = 1;
+ }
+
+ /*
+ * Set alarm for 5 seconds, we should be done way before that
+ */
+ memset(&act, 0, sizeof(act));
+ act.sa_handler = sig_alrm;
+ sigaction(SIGALRM, &act, NULL);
+ alarm(5);
+
+ ret = io_uring_submit(&ring);
+ if (ret != BUFFERS) {
+ fprintf(stderr, "submit=%d\n", ret);
+ goto err;
+ }
+
+ ret = T_EXIT_PASS;
+ i = 0;
+ do {
+ ret = io_uring_peek_cqe(&ring, &cqe);
+ if (ret)
+ continue;
+ io_uring_cqe_seen(&ring, cqe);
+ i++;
+ } while (i < BUFFERS);
+
+err:
+ if (fd != -1)
+ close(fd);
+ io_uring_queue_exit(&ring);
+ return ret;
+}
+
/*
* if we are polling io_uring_submit needs to always enter the
* kernel to fetch events
@@ -367,6 +438,15 @@ int main(int argc, char *argv[])
goto err;
}
+ /*
+ * Keep this last, it exits on failure
+ */
+ ret = test_io_uring_cqe_peek(fname);
+ if (ret) {
+ fprintf(stderr, "test_io_uring_cqe_peek failed\n");
+ goto err;
+ }
+
if (fname != argv[1])
unlink(fname);
return T_EXIT_PASS;
