1 /* SPDX-License-Identifier: MIT */
2 /*
3 * Description: test disable/enable notifications through eventfd
4 *
5 */
6 #include <errno.h>
7 #include <stdio.h>
8 #include <unistd.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <fcntl.h>
12 #include <poll.h>
13 #include <sys/eventfd.h>
14
15 #include "liburing.h"
16 #include "helpers.h"
17
test(bool defer)18 static int test(bool defer)
19 {
20 struct io_uring_params p = {};
21 struct io_uring_sqe *sqe;
22 struct io_uring_cqe *cqe;
23 struct io_uring ring;
24 uint64_t ptr;
25 struct iovec vec = {
26 .iov_base = &ptr,
27 .iov_len = sizeof(ptr)
28 };
29 int ret, evfd, i;
30
31 if (defer)
32 p.flags |= IORING_SETUP_SINGLE_ISSUER |
33 IORING_SETUP_DEFER_TASKRUN;
34
35 ret = io_uring_queue_init_params(64, &ring, &p);
36 if (ret) {
37 fprintf(stderr, "ring setup failed: %d\n", ret);
38 return T_EXIT_FAIL;
39 }
40
41 evfd = eventfd(0, EFD_CLOEXEC);
42 if (evfd < 0) {
43 perror("eventfd");
44 return T_EXIT_FAIL;
45 }
46
47 ret = io_uring_register_eventfd(&ring, evfd);
48 if (ret) {
49 fprintf(stderr, "failed to register evfd: %d\n", ret);
50 return T_EXIT_FAIL;
51 }
52
53 if (!io_uring_cq_eventfd_enabled(&ring)) {
54 fprintf(stderr, "eventfd disabled\n");
55 return T_EXIT_FAIL;
56 }
57
58 ret = io_uring_cq_eventfd_toggle(&ring, false);
59 if (ret) {
60 fprintf(stdout, "Skipping, CQ flags not available!\n");
61 return T_EXIT_SKIP;
62 }
63
64 sqe = io_uring_get_sqe(&ring);
65 io_uring_prep_readv(sqe, evfd, &vec, 1, 0);
66 sqe->user_data = 1;
67
68 ret = io_uring_submit(&ring);
69 if (ret != 1) {
70 fprintf(stderr, "submit: %d\n", ret);
71 return T_EXIT_FAIL;
72 }
73
74 for (i = 0; i < 63; i++) {
75 sqe = io_uring_get_sqe(&ring);
76 io_uring_prep_nop(sqe);
77 sqe->user_data = 2;
78 }
79
80 ret = io_uring_submit(&ring);
81 if (ret != 63) {
82 fprintf(stderr, "submit: %d\n", ret);
83 return T_EXIT_FAIL;
84 }
85
86 for (i = 0; i < 63; i++) {
87 ret = io_uring_wait_cqe(&ring, &cqe);
88 if (ret) {
89 fprintf(stderr, "wait: %d\n", ret);
90 return T_EXIT_FAIL;
91 }
92
93 switch (cqe->user_data) {
94 case 1: /* eventfd */
95 fprintf(stderr, "eventfd unexpected: %d\n", (int)ptr);
96 return T_EXIT_FAIL;
97 case 2:
98 if (cqe->res) {
99 fprintf(stderr, "nop: %d\n", cqe->res);
100 return T_EXIT_FAIL;
101 }
102 break;
103 }
104 io_uring_cqe_seen(&ring, cqe);
105 }
106
107 ret = io_uring_cq_eventfd_toggle(&ring, true);
108 if (ret) {
109 fprintf(stderr, "io_uring_cq_eventfd_toggle: %d\n", ret);
110 return T_EXIT_FAIL;
111 }
112
113 sqe = io_uring_get_sqe(&ring);
114 io_uring_prep_nop(sqe);
115 sqe->user_data = 2;
116
117 ret = io_uring_submit(&ring);
118 if (ret != 1) {
119 fprintf(stderr, "submit: %d\n", ret);
120 return T_EXIT_FAIL;
121 }
122
123 for (i = 0; i < 2; i++) {
124 ret = io_uring_wait_cqe(&ring, &cqe);
125 if (ret) {
126 fprintf(stderr, "wait: %d\n", ret);
127 return T_EXIT_FAIL;
128 }
129
130 switch (cqe->user_data) {
131 case 1: /* eventfd */
132 if (cqe->res != sizeof(ptr)) {
133 fprintf(stderr, "read res: %d\n", cqe->res);
134 return T_EXIT_FAIL;
135 }
136
137 if (ptr != 1) {
138 fprintf(stderr, "eventfd: %d\n", (int)ptr);
139 return T_EXIT_FAIL;
140 }
141 break;
142 case 2:
143 if (cqe->res) {
144 fprintf(stderr, "nop: %d\n", cqe->res);
145 return T_EXIT_FAIL;
146 }
147 break;
148 }
149 io_uring_cqe_seen(&ring, cqe);
150 }
151
152 io_uring_queue_exit(&ring);
153 close(evfd);
154 return T_EXIT_PASS;
155 }
156
main(int argc,char * argv[])157 int main(int argc, char *argv[])
158 {
159 int ret;
160
161 if (argc > 1)
162 return T_EXIT_SKIP;
163
164 ret = test(false);
165 if (ret != T_EXIT_PASS) {
166 fprintf(stderr, "%s: test(false) failed\n", argv[0]);
167 return ret;
168 }
169
170 if (t_probe_defer_taskrun()) {
171 ret = test(true);
172 if (ret != T_EXIT_PASS) {
173 fprintf(stderr, "%s: test(true) failed\n", argv[0]);
174 return ret;
175 }
176 }
177
178 return ret;
179 }
180