xref: /aosp_15_r20/external/liburing/test/poll-v-poll.c (revision 25da2bea747f3a93b4c30fd9708b0618ef55a0e6)
1 /* SPDX-License-Identifier: MIT */
2 /*
3  * Description: test io_uring poll handling
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 <fcntl.h>
13 #include <poll.h>
14 #include <sys/wait.h>
15 #include <sys/select.h>
16 #include <pthread.h>
17 #include <sys/epoll.h>
18 
19 #include "liburing.h"
20 
21 struct thread_data {
22 	struct io_uring *ring;
23 	int fd;
24 	int events;
25 	const char *test;
26 	int out[2];
27 };
28 
epoll_wait_fn(void * data)29 static void *epoll_wait_fn(void *data)
30 {
31 	struct thread_data *td = data;
32 	struct epoll_event ev;
33 
34 	if (epoll_wait(td->fd, &ev, 1, -1) < 0) {
35 		perror("epoll_wait");
36 		goto err;
37 	}
38 
39 	return NULL;
40 err:
41 	return (void *) 1;
42 }
43 
iou_poll(void * data)44 static void *iou_poll(void *data)
45 {
46 	struct thread_data *td = data;
47 	struct io_uring_sqe *sqe;
48 	struct io_uring_cqe *cqe;
49 	int ret;
50 
51 	sqe = io_uring_get_sqe(td->ring);
52 	io_uring_prep_poll_add(sqe, td->fd, td->events);
53 
54 	ret = io_uring_submit(td->ring);
55 	if (ret != 1) {
56 		fprintf(stderr, "submit got %d\n", ret);
57 		goto err;
58 	}
59 
60 	ret = io_uring_wait_cqe(td->ring, &cqe);
61 	if (ret) {
62 		fprintf(stderr, "wait_cqe: %d\n", ret);
63 		goto err;
64 	}
65 
66 	td->out[0] = cqe->res & 0x3f;
67 	io_uring_cqe_seen(td->ring, cqe);
68 	return NULL;
69 err:
70 	return (void *) 1;
71 }
72 
poll_pipe(void * data)73 static void *poll_pipe(void *data)
74 {
75 	struct thread_data *td = data;
76 	struct pollfd pfd;
77 	int ret;
78 
79 	pfd.fd = td->fd;
80 	pfd.events = td->events;
81 
82 	ret = poll(&pfd, 1, -1);
83 	if (ret < 0)
84 		perror("poll");
85 
86 	td->out[1] = pfd.revents;
87 	return NULL;
88 }
89 
do_pipe_pollin_test(struct io_uring * ring)90 static int do_pipe_pollin_test(struct io_uring *ring)
91 {
92 	struct thread_data td;
93 	pthread_t threads[2];
94 	int ret, pipe1[2];
95 	char buf;
96 
97 	if (pipe(pipe1) < 0) {
98 		perror("pipe");
99 		return 1;
100 	}
101 
102 	td.ring = ring;
103 	td.fd = pipe1[0];
104 	td.events = POLLIN;
105 	td.test = __FUNCTION__;
106 
107 	pthread_create(&threads[1], NULL, iou_poll, &td);
108 	pthread_create(&threads[0], NULL, poll_pipe, &td);
109 	usleep(100000);
110 
111 	buf = 0x89;
112 	ret = write(pipe1[1], &buf, sizeof(buf));
113 	if (ret != sizeof(buf)) {
114 		fprintf(stderr, "write failed: %d\n", ret);
115 		return 1;
116 	}
117 
118 	pthread_join(threads[0], NULL);
119 	pthread_join(threads[1], NULL);
120 
121 	if (td.out[0] != td.out[1]) {
122 		fprintf(stderr, "%s: res %x/%x differ\n", __FUNCTION__,
123 							td.out[0], td.out[1]);
124 		return 1;
125 	}
126 	return 0;
127 }
128 
do_pipe_pollout_test(struct io_uring * ring)129 static int do_pipe_pollout_test(struct io_uring *ring)
130 {
131 	struct thread_data td;
132 	pthread_t threads[2];
133 	int ret, pipe1[2];
134 	char buf;
135 
136 	if (pipe(pipe1) < 0) {
137 		perror("pipe");
138 		return 1;
139 	}
140 
141 	td.ring = ring;
142 	td.fd = pipe1[1];
143 	td.events = POLLOUT;
144 	td.test = __FUNCTION__;
145 
146 	pthread_create(&threads[0], NULL, poll_pipe, &td);
147 	pthread_create(&threads[1], NULL, iou_poll, &td);
148 	usleep(100000);
149 
150 	buf = 0x89;
151 	ret = write(pipe1[1], &buf, sizeof(buf));
152 	if (ret != sizeof(buf)) {
153 		fprintf(stderr, "write failed: %d\n", ret);
154 		return 1;
155 	}
156 
157 	pthread_join(threads[0], NULL);
158 	pthread_join(threads[1], NULL);
159 
160 	if (td.out[0] != td.out[1]) {
161 		fprintf(stderr, "%s: res %x/%x differ\n", __FUNCTION__,
162 							td.out[0], td.out[1]);
163 		return 1;
164 	}
165 
166 	return 0;
167 }
168 
do_fd_test(struct io_uring * ring,const char * fname,int events)169 static int do_fd_test(struct io_uring *ring, const char *fname, int events)
170 {
171 	struct thread_data td;
172 	pthread_t threads[2];
173 	int fd;
174 
175 	fd = open(fname, O_RDONLY);
176 	if (fd < 0) {
177 		perror("open");
178 		return 1;
179 	}
180 
181 	td.ring = ring;
182 	td.fd = fd;
183 	td.events = events;
184 	td.test = __FUNCTION__;
185 
186 	pthread_create(&threads[0], NULL, poll_pipe, &td);
187 	pthread_create(&threads[1], NULL, iou_poll, &td);
188 
189 	pthread_join(threads[0], NULL);
190 	pthread_join(threads[1], NULL);
191 
192 	if (td.out[0] != td.out[1]) {
193 		fprintf(stderr, "%s: res %x/%x differ\n", __FUNCTION__,
194 							td.out[0], td.out[1]);
195 		return 1;
196 	}
197 
198 	return 0;
199 }
200 
iou_epoll_ctl(struct io_uring * ring,int epfd,int fd,struct epoll_event * ev)201 static int iou_epoll_ctl(struct io_uring *ring, int epfd, int fd,
202 			 struct epoll_event *ev)
203 {
204 	struct io_uring_sqe *sqe;
205 	struct io_uring_cqe *cqe;
206 	int ret;
207 
208 	sqe = io_uring_get_sqe(ring);
209 	if (!sqe) {
210 		fprintf(stderr, "Failed to get sqe\n");
211 		return 1;
212 	}
213 
214 	io_uring_prep_epoll_ctl(sqe, epfd, fd, EPOLL_CTL_ADD, ev);
215 
216 	ret = io_uring_submit(ring);
217 	if (ret != 1) {
218 		fprintf(stderr, "submit: %d\n", ret);
219 		return 1;
220 	}
221 
222 	ret = io_uring_wait_cqe(ring, &cqe);
223 	if (ret) {
224 		fprintf(stderr, "wait_cqe: %d\n", ret);
225 		return 1;
226 	}
227 
228 	ret = cqe->res;
229 	io_uring_cqe_seen(ring, cqe);
230 	return ret;
231 }
232 
do_test_epoll(struct io_uring * ring,int iou_epoll_add)233 static int do_test_epoll(struct io_uring *ring, int iou_epoll_add)
234 {
235 	struct epoll_event ev;
236 	struct thread_data td;
237 	pthread_t threads[2];
238 	int ret, pipe1[2];
239 	char buf;
240 	int fd;
241 
242 	fd = epoll_create1(0);
243 	if (fd < 0) {
244 		perror("epoll_create");
245 		return 1;
246 	}
247 
248 	if (pipe(pipe1) < 0) {
249 		perror("pipe");
250 		return 1;
251 	}
252 
253 	ev.events = EPOLLIN;
254 	ev.data.fd = pipe1[0];
255 
256 	if (!iou_epoll_add) {
257 		if (epoll_ctl(fd, EPOLL_CTL_ADD, pipe1[0], &ev) < 0) {
258 			perror("epoll_ctrl");
259 			return 1;
260 		}
261 	} else {
262 		ret = iou_epoll_ctl(ring, fd, pipe1[0], &ev);
263 		if (ret == -EINVAL) {
264 			fprintf(stdout, "epoll not supported, skipping\n");
265 			return 0;
266 		} else if (ret < 0) {
267 			return 1;
268 		}
269 	}
270 
271 	td.ring = ring;
272 	td.fd = fd;
273 	td.events = POLLIN;
274 	td.test = __FUNCTION__;
275 
276 	pthread_create(&threads[0], NULL, iou_poll, &td);
277 	pthread_create(&threads[1], NULL, epoll_wait_fn, &td);
278 	usleep(100000);
279 
280 	buf = 0x89;
281 	ret = write(pipe1[1], &buf, sizeof(buf));
282 	if (ret != sizeof(buf)) {
283 		fprintf(stderr, "write failed: %d\n", ret);
284 		return 1;
285 	}
286 
287 	pthread_join(threads[0], NULL);
288 	pthread_join(threads[1], NULL);
289 	return 0;
290 }
291 
main(int argc,char * argv[])292 int main(int argc, char *argv[])
293 {
294 	struct io_uring ring;
295 	const char *fname;
296 	int ret;
297 
298 	ret = io_uring_queue_init(1, &ring, 0);
299 	if (ret) {
300 		fprintf(stderr, "ring setup failed\n");
301 		return 1;
302 	}
303 
304 	ret = do_pipe_pollin_test(&ring);
305 	if (ret) {
306 		fprintf(stderr, "pipe pollin test failed\n");
307 		return ret;
308 	}
309 
310 	ret = do_pipe_pollout_test(&ring);
311 	if (ret) {
312 		fprintf(stderr, "pipe pollout test failed\n");
313 		return ret;
314 	}
315 
316 	ret = do_test_epoll(&ring, 0);
317 	if (ret) {
318 		fprintf(stderr, "epoll test 0 failed\n");
319 		return ret;
320 	}
321 
322 	ret = do_test_epoll(&ring, 1);
323 	if (ret) {
324 		fprintf(stderr, "epoll test 1 failed\n");
325 		return ret;
326 	}
327 
328 	if (argc > 1)
329 		fname = argv[1];
330 	else
331 		fname = argv[0];
332 
333 	ret = do_fd_test(&ring, fname, POLLIN);
334 	if (ret) {
335 		fprintf(stderr, "fd test IN failed\n");
336 		return ret;
337 	}
338 
339 	ret = do_fd_test(&ring, fname, POLLOUT);
340 	if (ret) {
341 		fprintf(stderr, "fd test OUT failed\n");
342 		return ret;
343 	}
344 
345 	ret = do_fd_test(&ring, fname, POLLOUT | POLLIN);
346 	if (ret) {
347 		fprintf(stderr, "fd test IN|OUT failed\n");
348 		return ret;
349 	}
350 
351 	return 0;
352 
353 }
354