blob: afde4916145ecc618f070ff76ac00c0376aab164 [file] [log] [blame]
Jens Axboe3e4deca2019-11-22 07:23:56 -07001/*
2 * Description: test many files being polled for
3 *
4 */
5#include <errno.h>
6#include <stdio.h>
7#include <unistd.h>
8#include <stdlib.h>
9#include <string.h>
10#include <signal.h>
11#include <sys/poll.h>
12#include <sys/resource.h>
13#include <fcntl.h>
14
15#include "liburing.h"
16
17#define NFILES 5000
18#define BATCH 500
19#define NLOOPS 1000
20
21#define RING_SIZE 512
22
23struct p {
24 int fd[2];
25 int triggered;
26};
27
28static struct p p[NFILES];
29
30static int arm_poll(struct io_uring *ring, int off)
31{
32 struct io_uring_sqe *sqe;
33
34 sqe = io_uring_get_sqe(ring);
35 if (!sqe) {
36 fprintf(stderr, "failed getting sqe\n");
37 return 1;
38 }
39
40 io_uring_prep_poll_add(sqe, p[off].fd[0], POLLIN);
41 sqe->user_data = off;
42 return 0;
43}
44
45static int reap_polls(struct io_uring *ring)
46{
47 struct io_uring_cqe *cqe;
48 int i, ret, off;
49 char c;
50
51 for (i = 0; i < BATCH; i++) {
52 ret = io_uring_wait_cqe(ring, &cqe);
53 if (ret) {
54 fprintf(stderr, "wait cqe %d\n", ret);
55 return ret;
56 }
57 off = cqe->user_data;
58 p[off].triggered = 0;
59 ret = read(p[off].fd[0], &c, 1);
60 if (ret != 1) {
61 fprintf(stderr, "read got %d/%d\n", ret, errno);
62 break;
63 }
64 if (arm_poll(ring, off))
65 break;
66 io_uring_cqe_seen(ring, cqe);
67 }
68
69 if (i != BATCH) {
70 fprintf(stderr, "gave up at %d\n", i);
71 return 1;
72 }
73
74 ret = io_uring_submit(ring);
75 if (ret != BATCH) {
76 fprintf(stderr, "submitted %d, %d\n", ret, BATCH);
77 return 1;
78 }
79
80 return 0;
81}
82
83static int trigger_polls(void)
84{
85 char c = 89;
86 int i, ret;
87
88 for (i = 0; i < BATCH; i++) {
89 int off;
90
91 do {
92 off = rand() % NFILES;
93 if (!p[off].triggered)
94 break;
95 } while (1);
96
97 p[off].triggered = 1;
98 ret = write(p[off].fd[1], &c, 1);
99 if (ret != 1) {
100 fprintf(stderr, "write got %d/%d\n", ret, errno);
101 return 1;
102 }
103 }
104
105 return 0;
106}
107
108static int arm_polls(struct io_uring *ring)
109{
110 int ret, to_arm = NFILES, i, off;
111
112 off = 0;
113 while (to_arm) {
114 int this_arm;
115
116 this_arm = to_arm;
117 if (this_arm > RING_SIZE)
118 this_arm = RING_SIZE;
119
120 for (i = 0; i < this_arm; i++) {
121 if (arm_poll(ring, off)) {
Jens Axboea8dc4972020-02-01 09:58:07 -0700122 fprintf(stderr, "arm failed at %d\n", off);
Jens Axboe3e4deca2019-11-22 07:23:56 -0700123 return 1;
124 }
125 off++;
126 }
127
128 ret = io_uring_submit(ring);
129 if (ret != this_arm) {
Jens Axboea8dc4972020-02-01 09:58:07 -0700130 fprintf(stderr, "submitted %d, %d\n", ret, this_arm);
Jens Axboe3e4deca2019-11-22 07:23:56 -0700131 return 1;
132 }
133 to_arm -= this_arm;
134 }
135
136 return 0;
137}
138
139int main(int argc, char *argv[])
140{
141 struct io_uring ring;
142 struct rlimit rlim;
143 int i, ret;
144
145 if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) {
146 perror("getrlimit");
147 goto err_noring;
148 }
149
150 if (rlim.rlim_cur < (2 * NFILES + 5)) {
151 rlim.rlim_cur = (2 * NFILES + 5);
152 rlim.rlim_max = rlim.rlim_cur;
153 if (setrlimit(RLIMIT_NOFILE, &rlim) < 0) {
154 if (errno == EPERM)
155 goto err_nofail;
156 perror("setrlimit");
157 goto err_noring;
158 }
159 }
160
161 for (i = 0; i < NFILES; i++) {
162 if (pipe(p[i].fd) < 0) {
163 perror("pipe");
164 goto err_noring;
165 }
166 }
167
168 if (io_uring_queue_init(RING_SIZE, &ring, 0)) {
169 fprintf(stderr, "failed ring init\n");
170 goto err_noring;
171 }
172
173 if (arm_polls(&ring))
174 goto err;
175
176 for (i = 0; i < NLOOPS; i++) {
177 trigger_polls();
178 ret = reap_polls(&ring);
179 if (ret)
180 goto err;
181 }
182
183 io_uring_queue_exit(&ring);
184 return 0;
185err:
186 io_uring_queue_exit(&ring);
187err_noring:
188 fprintf(stderr, "poll-many failed\n");
189 return 1;
190err_nofail:
191 fprintf(stderr, "poll-many: not enough files available (and not root), "
192 "skipped\n");
193 return 0;
194}