summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJens Axboe <axboe@kernel.dk>2021-04-06 15:07:36 -0600
committerJens Axboe <axboe@kernel.dk>2021-04-06 15:07:36 -0600
commitd3eb6af47886656e811e8f4e274ac361d0efa5bf (patch)
treebe37a48f7cd644c73226b8bcac88e80dfcc980c7
parentb75baa4f16d51c31f91a13f6ffd0918f99da97c8 (diff)
downloadliburing-d3eb6af47886656e811e8f4e274ac361d0efa5bf.tar.gz
liburing-d3eb6af47886656e811e8f4e274ac361d0efa5bf.tar.bz2
test/poll-mshot-update: test live updates of triggering requests
Signed-off-by: Jens Axboe <axboe@kernel.dk>
-rw-r--r--test/Makefile4
-rw-r--r--test/poll-mshot-update.c256
2 files changed, 260 insertions, 0 deletions
diff --git a/test/Makefile b/test/Makefile
index be34856..210571c 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -78,6 +78,7 @@ test_targets += \
poll-cancel-ton \
poll-link \
poll-many \
+ poll-mshot-update \
poll-ring \
poll-v-poll \
probe \
@@ -211,6 +212,8 @@ test_srcs := \
poll-cancel-ton.c \
poll-cancel.c \
poll-link.c \
+ poll-many.c \
+ poll-mshot-update.c \
poll-ring.c \
poll-v-poll.c \
poll.c \
@@ -269,6 +272,7 @@ pipe-eof: XCFLAGS = -lpthread
timeout-new: XCFLAGS = -lpthread
thread-exit: XCFLAGS = -lpthread
ring-leak2: XCFLAGS = -lpthread
+poll-mshot-update: XCFLAGS = -lpthread
install: $(test_targets) runtests.sh runtests-loop.sh
$(INSTALL) -D -d -m 755 $(datadir)/liburing-test/
diff --git a/test/poll-mshot-update.c b/test/poll-mshot-update.c
new file mode 100644
index 0000000..bfe96c8
--- /dev/null
+++ b/test/poll-mshot-update.c
@@ -0,0 +1,256 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Description: test many files being polled for and updated
+ *
+ */
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/poll.h>
+#include <sys/resource.h>
+#include <fcntl.h>
+#include <pthread.h>
+
+#include "liburing.h"
+
+#define NFILES 5000
+#define BATCH 500
+#define NLOOPS 1000
+
+#define RING_SIZE 512
+
+struct p {
+ int fd[2];
+ int triggered;
+};
+
+static struct p p[NFILES];
+static int no_update;
+
+static int arm_poll(struct io_uring *ring, int off)
+{
+ struct io_uring_sqe *sqe;
+
+ sqe = io_uring_get_sqe(ring);
+ if (!sqe) {
+ fprintf(stderr, "failed getting sqe\n");
+ return 1;
+ }
+
+ io_uring_prep_poll_add(sqe, p[off].fd[0], POLLIN);
+ sqe->len = 1;
+ sqe->user_data = off;
+ return 0;
+}
+
+static int reap_polls(struct io_uring *ring)
+{
+ struct io_uring_cqe *cqe;
+ int i, ret, off;
+ char c;
+
+ for (i = 0; i < BATCH; i++) {
+ struct io_uring_sqe *sqe;
+
+ sqe = io_uring_get_sqe(ring);
+ io_uring_prep_poll_add(sqe, p[i].fd[0], POLLIN);
+ sqe->user_data = 0x12345678;
+ sqe->addr = i;
+ sqe->off = POLLIN;
+ sqe->len = 2;
+ }
+
+ ret = io_uring_submit(ring);
+ if (ret != BATCH) {
+ fprintf(stderr, "submitted %d, %d\n", ret, BATCH);
+ return 1;
+ }
+
+ for (i = 0; i < 2 * BATCH; i++) {
+ ret = io_uring_wait_cqe(ring, &cqe);
+ if (ret) {
+ fprintf(stderr, "wait cqe %d\n", ret);
+ return ret;
+ }
+ off = cqe->user_data;
+ if (off == 0x12345678)
+ goto seen;
+ p[off].triggered = 0;
+ ret = read(p[off].fd[0], &c, 1);
+ if (ret != 1) {
+ if (ret == -1 && errno == EAGAIN)
+ goto seen;
+ fprintf(stderr, "read got %d/%d\n", ret, errno);
+ break;
+ }
+seen:
+ io_uring_cqe_seen(ring, cqe);
+ }
+
+ if (i != 2 * BATCH) {
+ fprintf(stderr, "gave up at %d\n", i);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int trigger_polls(void)
+{
+ char c = 89;
+ int i, ret;
+
+ for (i = 0; i < BATCH; i++) {
+ int off;
+
+ do {
+ off = rand() % NFILES;
+ if (!p[off].triggered)
+ break;
+ } while (1);
+
+ p[off].triggered = 1;
+ ret = write(p[off].fd[1], &c, 1);
+ if (ret != 1) {
+ fprintf(stderr, "write got %d/%d\n", ret, errno);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static void *trigger_polls_fn(void *data)
+{
+ trigger_polls();
+ return NULL;
+}
+
+static int check_no_update(struct io_uring *ring)
+{
+ struct io_uring_cqe *cqe;
+ int ret;
+
+ ret = io_uring_wait_cqe(ring, &cqe);
+ if (ret)
+ return 0;
+ ret = cqe->res;
+ io_uring_cqe_seen(ring, cqe);
+ return ret == -EINVAL;
+}
+
+static int arm_polls(struct io_uring *ring)
+{
+ int ret, to_arm = NFILES, i, off;
+
+ off = 0;
+ while (to_arm) {
+ int this_arm;
+
+ this_arm = to_arm;
+ if (this_arm > RING_SIZE)
+ this_arm = RING_SIZE;
+
+ for (i = 0; i < this_arm; i++) {
+ if (arm_poll(ring, off)) {
+ fprintf(stderr, "arm failed at %d\n", off);
+ return 1;
+ }
+ off++;
+ }
+
+ ret = io_uring_submit(ring);
+ if (ret != this_arm) {
+ if (ret > 0 && check_no_update(ring)) {
+ no_update = 1;
+ return 0;
+ }
+ fprintf(stderr, "submitted %d, %d\n", ret, this_arm);
+ return 1;
+ }
+ to_arm -= this_arm;
+ }
+
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ struct io_uring ring;
+ struct io_uring_params params = { };
+ struct rlimit rlim;
+ pthread_t thread;
+ int i, ret;
+
+ if (argc > 1)
+ return 0;
+
+ if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) {
+ perror("getrlimit");
+ goto err_noring;
+ }
+
+ if (rlim.rlim_cur < (2 * NFILES + 5)) {
+ rlim.rlim_cur = (2 * NFILES + 5);
+ rlim.rlim_max = rlim.rlim_cur;
+ if (setrlimit(RLIMIT_NOFILE, &rlim) < 0) {
+ if (errno == EPERM)
+ goto err_nofail;
+ perror("setrlimit");
+ goto err_noring;
+ }
+ }
+
+ for (i = 0; i < NFILES; i++) {
+ if (pipe(p[i].fd) < 0) {
+ perror("pipe");
+ goto err_noring;
+ }
+ fcntl(p[i].fd[0], F_SETFL, O_NONBLOCK);
+ }
+
+ params.flags = IORING_SETUP_CQSIZE;
+ params.cq_entries = 4096;
+ ret = io_uring_queue_init_params(RING_SIZE, &ring, &params);
+ if (ret) {
+ if (ret == -EINVAL) {
+ fprintf(stdout, "No CQSIZE, trying without\n");
+ ret = io_uring_queue_init(RING_SIZE, &ring, 0);
+ if (ret) {
+ fprintf(stderr, "ring setup failed: %d\n", ret);
+ return 1;
+ }
+ }
+ }
+
+ if (arm_polls(&ring))
+ goto err;
+ if (no_update) {
+ printf("No poll update support, skipping\n");
+ goto done;
+ }
+
+ for (i = 0; i < NLOOPS; i++) {
+ pthread_create(&thread, NULL, trigger_polls_fn, NULL);
+ ret = reap_polls(&ring);
+ if (ret)
+ goto err;
+ pthread_join(thread, NULL);
+ }
+
+done:
+ io_uring_queue_exit(&ring);
+ return 0;
+err:
+ io_uring_queue_exit(&ring);
+err_noring:
+ fprintf(stderr, "poll-many failed\n");
+ return 1;
+err_nofail:
+ fprintf(stderr, "poll-many: not enough files available (and not root), "
+ "skipped\n");
+ return 0;
+}