blob: c8ba6f10a03f278e06a54fa3d48a03135a3d167e [file] [log] [blame]
Jens Axboee5024352020-02-11 20:34:12 -07001/* SPDX-License-Identifier: MIT */
Jens Axboed6440b02019-12-22 20:29:04 -07002/*
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 <sys/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
21struct thread_data {
22 struct io_uring *ring;
23 int fd;
24 int events;
25 const char *test;
26 int out[2];
27};
28
29static 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;
40err:
41 return (void *) 1;
42}
43
44static 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;
69err:
70 return (void *) 1;
71}
72
73static 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
90static 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
129static 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
169static 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
Jens Axboead428762020-02-06 09:56:59 -0700201static 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
233static int do_test_epoll(struct io_uring *ring, int iou_epoll_add)
Jens Axboed6440b02019-12-22 20:29:04 -0700234{
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
Jens Axboead428762020-02-06 09:56:59 -0700256 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 {
Guillem Jover1fb41602020-02-11 00:45:47 +0100262 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) {
Jens Axboead428762020-02-06 09:56:59 -0700267 return 1;
Guillem Jover1fb41602020-02-11 00:45:47 +0100268 }
Jens Axboed6440b02019-12-22 20:29:04 -0700269 }
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
292int 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
Jens Axboead428762020-02-06 09:56:59 -0700316 ret = do_test_epoll(&ring, 0);
Jens Axboed6440b02019-12-22 20:29:04 -0700317 if (ret) {
Jens Axboead428762020-02-06 09:56:59 -0700318 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");
Jens Axboed6440b02019-12-22 20:29:04 -0700325 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}