summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJens Axboe <axboe@kernel.dk>2019-11-22 07:23:56 -0700
committerJens Axboe <axboe@kernel.dk>2019-11-22 07:23:56 -0700
commit3e4deca46292243e3d93c372e94a272b4a4ddcc6 (patch)
treecfcc2c03df5bf344503abc94aee989727b1ea0e5
parent4db698dcf2b6c4fd28cab691fca446984ac0ddbb (diff)
downloadliburing-3e4deca46292243e3d93c372e94a272b4a4ddcc6.tar.gz
liburing-3e4deca46292243e3d93c372e94a272b4a4ddcc6.tar.bz2
Add test/poll-many.c
This tests for many (thousands) of files being polle for, triggering POLLIN events, and re-arming. Signed-off-by: Jens Axboe <axboe@kernel.dk>
-rw-r--r--test/Makefile5
-rw-r--r--test/poll-many.c194
2 files changed, 197 insertions, 2 deletions
diff --git a/test/Makefile b/test/Makefile
index 60ae08f..b4aa6b3 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -10,7 +10,8 @@ all_targets += poll poll-cancel ring-leak fsync io_uring_setup io_uring_register
cq-size 8a9973408177-test a0908ae19763-test 232c93d07b74-test \
socket-rw accept timeout-overflow defer read-write io-cancel \
link-timeout cq-overflow link_drain fc2a85cb02ef-test \
- poll-link accept-link fixed-link poll-cancel-ton teardowns
+ poll-link accept-link fixed-link poll-cancel-ton teardowns \
+ poll-many
include ../Makefile.quiet
@@ -28,7 +29,7 @@ test_srcs := poll.c poll-cancel.c ring-leak.c fsync.c io_uring_setup.c \
a0908ae19763-test.c 232c93d07b74-test.c socket-rw.c accept.c \
timeout-overflow.c defer.c read-write.c io-cancel.c link-timeout.c \
cq-overflow.c link_drain.c fc2a85cb02ef-test.c poll-link.c \
- accept-link.c fixed-link.c poll-cancel-ton.c teardowns.c
+ accept-link.c fixed-link.c poll-cancel-ton.c teardowns.c poll-many.c
test_objs := $(patsubst %.c,%.ol,$(test_srcs))
diff --git a/test/poll-many.c b/test/poll-many.c
new file mode 100644
index 0000000..695c14c
--- /dev/null
+++ b/test/poll-many.c
@@ -0,0 +1,194 @@
+/*
+ * Description: test many files being polled for
+ *
+ */
+#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 "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 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->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++) {
+ ret = io_uring_wait_cqe(ring, &cqe);
+ if (ret) {
+ fprintf(stderr, "wait cqe %d\n", ret);
+ return ret;
+ }
+ off = cqe->user_data;
+ p[off].triggered = 0;
+ ret = read(p[off].fd[0], &c, 1);
+ if (ret != 1) {
+ fprintf(stderr, "read got %d/%d\n", ret, errno);
+ break;
+ }
+ if (arm_poll(ring, off))
+ break;
+ io_uring_cqe_seen(ring, cqe);
+ }
+
+ if (i != BATCH) {
+ fprintf(stderr, "gave up at %d\n", i);
+ return 1;
+ }
+
+ ret = io_uring_submit(ring);
+ if (ret != BATCH) {
+ fprintf(stderr, "submitted %d, %d\n", ret, BATCH);
+ 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 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)) {
+ printf("arm failed at %d\n", off);
+ return 1;
+ }
+ off++;
+ }
+
+ ret = io_uring_submit(ring);
+ if (ret != this_arm) {
+ printf("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 rlimit rlim;
+ int i, ret;
+
+ 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;
+ }
+ }
+
+ if (io_uring_queue_init(RING_SIZE, &ring, 0)) {
+ fprintf(stderr, "failed ring init\n");
+ goto err_noring;
+ }
+
+ if (arm_polls(&ring))
+ goto err;
+
+ for (i = 0; i < NLOOPS; i++) {
+ trigger_polls();
+ ret = reap_polls(&ring);
+ if (ret)
+ goto err;
+ }
+
+ 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;
+}