1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) 2016 Fujitsu Ltd.
4 * Author: Guangwen Feng <[email protected]>
5 */
6
7 /*\
8 * [Description]
9 *
10 * Basic test for epoll_wait. Check that epoll_wait works for EPOLLOUT and
11 * EPOLLIN events on an epoll instance and that struct epoll_event is set
12 * correctly.
13 */
14
15 #include <sys/epoll.h>
16 #include <poll.h>
17 #include <string.h>
18 #include <errno.h>
19
20 #include "tst_test.h"
21
22 static int write_size, epfd, fds[2];
23
get_writesize(void)24 static int get_writesize(void)
25 {
26 int nfd, write_size = 0;
27 char buf[4096];
28 struct pollfd pfd[] = {
29 {.fd = fds[1], .events = POLLOUT},
30 };
31
32 memset(buf, 'a', sizeof(buf));
33
34 do {
35 write_size += SAFE_WRITE(SAFE_WRITE_ANY, fds[1], buf, sizeof(buf));
36 nfd = poll(pfd, 1, 1);
37 if (nfd == -1)
38 tst_brk(TBROK | TERRNO, "poll() failed");
39 } while (nfd > 0);
40
41 char read_buf[write_size];
42
43 SAFE_READ(1, fds[0], read_buf, sizeof(read_buf));
44
45 tst_res(TINFO, "Pipe buffer size is %i bytes", write_size);
46
47 return write_size;
48 }
49
setup(void)50 static void setup(void)
51 {
52 static struct epoll_event epevs[2] = {
53 {.events = EPOLLIN},
54 {.events = EPOLLOUT},
55 };
56
57 SAFE_PIPE(fds);
58
59 epevs[0].data.fd = fds[0];
60 epevs[1].data.fd = fds[1];
61
62 write_size = get_writesize();
63
64 epfd = epoll_create(3);
65 if (epfd == -1)
66 tst_brk(TBROK | TERRNO, "epoll_create() failed");
67
68 if (epoll_ctl(epfd, EPOLL_CTL_ADD, fds[0], &epevs[0]) ||
69 epoll_ctl(epfd, EPOLL_CTL_ADD, fds[1], &epevs[1])) {
70 tst_brk(TBROK | TERRNO, "epoll_ctl() failed");
71 }
72 }
73
has_event(struct epoll_event * epevs,int epevs_len,int fd,uint32_t events)74 static int has_event(struct epoll_event *epevs, int epevs_len,
75 int fd, uint32_t events)
76 {
77 int i;
78
79 for (i = 0; i < epevs_len; i++) {
80 if ((epevs[i].data.fd == fd) && (epevs[i].events == events))
81 return 1;
82 }
83
84 return 0;
85 }
86
dump_epevs(struct epoll_event * epevs,int epevs_len)87 static void dump_epevs(struct epoll_event *epevs, int epevs_len)
88 {
89 int i;
90
91 for (i = 0; i < epevs_len; i++) {
92 tst_res(TINFO, "epevs[%d]: epoll.data.fd %d, epoll.events %x",
93 i, epevs[i].data.fd, epevs[i].events);
94 }
95 }
96
verify_epollout(void)97 static void verify_epollout(void)
98 {
99 struct epoll_event ret_evs = {.events = 0, .data.fd = 0};
100
101 TEST(epoll_wait(epfd, &ret_evs, 1, -1));
102
103 if (TST_RET == -1) {
104 tst_res(TFAIL | TTERRNO, "epoll_wait() epollout failed");
105 return;
106 }
107
108 if (TST_RET != 1) {
109 tst_res(TFAIL, "epoll_wait() returned %li, expected 1",
110 TST_RET);
111 return;
112 }
113
114 if (ret_evs.data.fd != fds[1]) {
115 tst_res(TFAIL, "epoll.data.fd %i, expected %i",
116 ret_evs.data.fd, fds[1]);
117 return;
118 }
119
120 if (ret_evs.events != EPOLLOUT) {
121 tst_res(TFAIL, "epoll.events %x, expected EPOLLOUT %x",
122 ret_evs.events, EPOLLOUT);
123 return;
124 }
125
126 tst_res(TPASS, "epoll_wait() epollout");
127 }
128
verify_epollin(void)129 static void verify_epollin(void)
130 {
131 char write_buf[write_size];
132 char read_buf[sizeof(write_buf)];
133 struct epoll_event ret_evs = {.events = 0, .data.fd = 0};
134
135 memset(write_buf, 'a', sizeof(write_buf));
136
137 SAFE_WRITE(SAFE_WRITE_ALL, fds[1], write_buf, sizeof(write_buf));
138
139 TEST(epoll_wait(epfd, &ret_evs, 1, -1));
140
141 if (TST_RET == -1) {
142 tst_res(TFAIL | TTERRNO, "epoll_wait() epollin failed");
143 goto end;
144 }
145
146 if (TST_RET != 1) {
147 tst_res(TFAIL, "epoll_wait() returned %li, expected 1",
148 TST_RET);
149 goto end;
150 }
151
152 if (ret_evs.data.fd != fds[0]) {
153 tst_res(TFAIL, "epoll.data.fd %i, expected %i",
154 ret_evs.data.fd, fds[0]);
155 goto end;
156 }
157
158 if (ret_evs.events != EPOLLIN) {
159 tst_res(TFAIL, "epoll.events %x, expected EPOLLIN %x",
160 ret_evs.events, EPOLLIN);
161 goto end;
162 }
163
164 tst_res(TPASS, "epoll_wait() epollin");
165
166 end:
167 SAFE_READ(1, fds[0], read_buf, sizeof(write_buf));
168 }
169
verify_epollio(void)170 static void verify_epollio(void)
171 {
172 char write_buf[] = "Testing";
173 char read_buf[sizeof(write_buf)];
174 uint32_t events = EPOLLIN | EPOLLOUT;
175 struct epoll_event ret_evs[2];
176
177 SAFE_WRITE(SAFE_WRITE_ALL, fds[1], write_buf, sizeof(write_buf));
178
179 while (events) {
180 int events_matched = 0;
181
182 memset(ret_evs, 0, sizeof(ret_evs));
183 TEST(epoll_wait(epfd, ret_evs, 2, -1));
184
185 if (TST_RET <= 0) {
186 tst_res(TFAIL | TTERRNO, "epoll_wait() returned %li",
187 TST_RET);
188 goto end;
189 }
190
191 if ((events & EPOLLIN) &&
192 has_event(ret_evs, 2, fds[0], EPOLLIN)) {
193 events_matched++;
194 events &= ~EPOLLIN;
195 }
196
197 if ((events & EPOLLOUT) &&
198 has_event(ret_evs, 2, fds[1], EPOLLOUT)) {
199 events_matched++;
200 events &= ~EPOLLOUT;
201 }
202
203 if (TST_RET != events_matched) {
204 tst_res(TFAIL,
205 "epoll_wait() returned unexpected events");
206 dump_epevs(ret_evs, 2);
207 goto end;
208 }
209 }
210
211 tst_res(TPASS, "epoll_wait() epollio");
212
213 end:
214 SAFE_READ(1, fds[0], read_buf, sizeof(write_buf));
215 }
216
cleanup(void)217 static void cleanup(void)
218 {
219 if (epfd > 0)
220 SAFE_CLOSE(epfd);
221
222 if (fds[0]) {
223 SAFE_CLOSE(fds[0]);
224 SAFE_CLOSE(fds[1]);
225 }
226 }
227
228 static void (*testcase_list[])(void) = {
229 verify_epollout, verify_epollin, verify_epollio
230 };
231
do_test(unsigned int n)232 static void do_test(unsigned int n)
233 {
234 testcase_list[n]();
235 }
236
237 static struct tst_test test = {
238 .setup = setup,
239 .cleanup = cleanup,
240 .test = do_test,
241 .tcnt = ARRAY_SIZE(testcase_list),
242 };
243