1 /* SPDX-License-Identifier: MIT */
2 /*
3 * Test that we don't recursively generate completion events if an io_uring
4 * fd is added to an epoll context, and the ring itself polls for events on
5 * the epollfd. Older kernels will stop on overflow, newer kernels will
6 * detect this earlier and abort correctly.
7 */
8 #include <stdio.h>
9 #include <unistd.h>
10 #include <stdlib.h>
11 #include <sys/epoll.h>
12 #include <sys/types.h>
13 #include <poll.h>
14 #include "liburing.h"
15 #include "helpers.h"
16
main(int argc,char * argv[])17 int main(int argc, char *argv[])
18 {
19 struct io_uring ring;
20 struct io_uring_sqe *sqe;
21 struct io_uring_cqe *cqe;
22 struct epoll_event ev = { };
23 int epollfd, ret, i;
24
25 if (argc > 1)
26 return T_EXIT_SKIP;
27
28 ret = io_uring_queue_init(8, &ring, 0);
29 if (ret) {
30 fprintf(stderr, "Ring init failed: %d\n", ret);
31 return T_EXIT_FAIL;
32 }
33
34 epollfd = epoll_create1(0);
35 if (epollfd < 0) {
36 perror("epoll_create");
37 return T_EXIT_FAIL;
38 }
39
40 ev.events = EPOLLIN;
41 ev.data.fd = ring.ring_fd;
42 ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, ring.ring_fd, &ev);
43 if (ret < 0) {
44 perror("epoll_ctl");
45 return T_EXIT_FAIL;
46 }
47
48 sqe = io_uring_get_sqe(&ring);
49 io_uring_prep_poll_multishot(sqe, epollfd, POLLIN);
50 sqe->user_data = 1;
51 io_uring_submit(&ring);
52
53 sqe = io_uring_get_sqe(&ring);
54 sqe->user_data = 2;
55 io_uring_prep_nop(sqe);
56 io_uring_submit(&ring);
57
58 for (i = 0; i < 2; i++) {
59 ret = io_uring_wait_cqe(&ring, &cqe);
60 if (ret) {
61 fprintf(stderr, "wait_cqe ret = %d\n", ret);
62 break;
63 }
64 io_uring_cqe_seen(&ring, cqe);
65 }
66
67 ret = io_uring_peek_cqe(&ring, &cqe);
68 if (!ret) {
69 fprintf(stderr, "Generated too many events\n");
70 return T_EXIT_FAIL;
71 }
72
73 return T_EXIT_PASS;
74 }
75