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