xref: /aosp_15_r20/external/liburing/test/poll-many.c (revision 25da2bea747f3a93b4c30fd9708b0618ef55a0e6)
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, &params);
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