1 /*
2 * Copyright (c) 2016 Fujitsu Ltd.
3 * Author: Guangwen Feng <fenggw-fnst@cn.fujitsu.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
13 * the GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program.
17 */
18
19 /*
20 * Description:
21 * Basic test for epoll_wait(2).
22 * Check that epoll_wait(2) works for EPOLLOUT and EPOLLIN events
23 * on a epoll instance and that struct epoll_event is set correctly.
24 */
25
26 #include <sys/epoll.h>
27 #include <poll.h>
28 #include <string.h>
29 #include <errno.h>
30
31 #include "test.h"
32 #include "safe_macros.h"
33
34 char *TCID = "epoll_wait01";
35 int TST_TOTAL = 3;
36
37 static int write_size, epfd, fds[2], fds2[2];
38 static struct epoll_event epevs[3] = {
39 {.events = EPOLLIN},
40 {.events = EPOLLOUT},
41 {.events = EPOLLIN}
42 };
43
44 static void setup(void);
45 static int get_writesize(void);
46 static void verify_epollout(void);
47 static void verify_epollin(void);
48 static void verify_epollio(void);
49 static int has_event(struct epoll_event *, int, int, uint32_t);
50 static void dump_epevs(struct epoll_event *, int);
51 static void cleanup(void);
52
main(int ac,char ** av)53 int main(int ac, char **av)
54 {
55 int lc;
56
57 tst_parse_opts(ac, av, NULL, NULL);
58
59 setup();
60
61 for (lc = 0; TEST_LOOPING(lc); lc++) {
62 tst_count = 0;
63
64 verify_epollout();
65 verify_epollin();
66 verify_epollio();
67 }
68
69 cleanup();
70 tst_exit();
71 }
72
setup(void)73 static void setup(void)
74 {
75 tst_sig(NOFORK, DEF_HANDLER, cleanup);
76
77 TEST_PAUSE;
78
79 SAFE_PIPE(NULL, fds);
80 SAFE_PIPE(cleanup, fds2);
81
82 write_size = get_writesize();
83
84 epfd = epoll_create(3);
85 if (epfd == -1) {
86 tst_brkm(TBROK | TERRNO, cleanup,
87 "failed to create epoll instance");
88 }
89
90 epevs[0].data.fd = fds[0];
91 epevs[1].data.fd = fds[1];
92 epevs[2].data.fd = fds2[0];
93
94 if (epoll_ctl(epfd, EPOLL_CTL_ADD, fds[0], &epevs[0]) ||
95 epoll_ctl(epfd, EPOLL_CTL_ADD, fds[1], &epevs[1]) ||
96 epoll_ctl(epfd, EPOLL_CTL_ADD, fds2[0], &epevs[2])) {
97 tst_brkm(TBROK | TERRNO, cleanup,
98 "failed to register epoll target");
99 }
100 }
101
get_writesize(void)102 static int get_writesize(void)
103 {
104 int nfd, write_size = 0;
105 char buf[4096];
106
107 struct pollfd pfd[] = {
108 {.fd = fds[1], .events = POLLOUT},
109 };
110
111 memset(buf, 'a', sizeof(buf));
112
113 do {
114 write_size += SAFE_WRITE(cleanup, 0, fds[1], buf, sizeof(buf));
115 nfd = poll(pfd, 1, 1);
116 if (nfd == -1)
117 tst_brkm(TBROK | TERRNO, cleanup, "poll failed");
118 } while (nfd > 0);
119
120 char read_buf[write_size];
121
122 SAFE_READ(cleanup, 1, fds[0], read_buf, sizeof(read_buf));
123
124 tst_resm(TINFO, "Pipe buffer size is %i bytes", write_size);
125
126 return write_size;
127 }
128
verify_epollout(void)129 static void verify_epollout(void)
130 {
131 TEST(epoll_wait(epfd, epevs, 3, -1));
132
133 if (TEST_RETURN == -1) {
134 tst_resm(TFAIL | TTERRNO, "epoll_wait() epollout failed");
135 return;
136 }
137
138 if (TEST_RETURN != 1) {
139 tst_resm(TFAIL, "epoll_wait() returned %li, expected 1",
140 TEST_RETURN);
141 return;
142 }
143
144 if (epevs[0].data.fd != fds[1]) {
145 tst_resm(TFAIL, "epoll.data.fd %i, expected %i",
146 epevs[0].data.fd, fds[1]);
147 return;
148 }
149
150 if (epevs[0].events != EPOLLOUT) {
151 tst_resm(TFAIL, "epoll.events %x, expected EPOLLOUT %x",
152 epevs[0].events, EPOLLOUT);
153 return;
154 }
155
156 tst_resm(TPASS, "epoll_wait() epollout");
157 }
158
verify_epollin(void)159 static void verify_epollin(void)
160 {
161 char write_buf[write_size];
162 char read_buf[sizeof(write_buf)];
163
164 memset(write_buf, 'a', sizeof(write_buf));
165
166 SAFE_WRITE(cleanup, 1, fds[1], write_buf, sizeof(write_buf));
167
168 TEST(epoll_wait(epfd, epevs, 3, -1));
169
170 if (TEST_RETURN == -1) {
171 tst_resm(TFAIL | TTERRNO, "epoll_wait() epollin failed");
172 goto end;
173 }
174
175 if (TEST_RETURN != 1) {
176 tst_resm(TFAIL, "epoll_wait() returned %li, expected 1",
177 TEST_RETURN);
178 goto end;
179 }
180
181 if (epevs[0].data.fd != fds[0]) {
182 tst_resm(TFAIL, "epoll.data.fd %i, expected %i",
183 epevs[0].data.fd, fds[0]);
184 goto end;
185 }
186
187 if (epevs[0].events != EPOLLIN) {
188 tst_resm(TFAIL, "epoll.events %x, expected EPOLLIN %x",
189 epevs[0].events, EPOLLIN);
190 goto end;
191 }
192
193 tst_resm(TPASS, "epoll_wait() epollin");
194
195 end:
196 SAFE_READ(cleanup, 1, fds[0], read_buf, sizeof(write_buf));
197 }
198
verify_epollio(void)199 static void verify_epollio(void)
200 {
201 char write_buf[] = "Testing";
202 char read_buf[sizeof(write_buf)];
203
204 SAFE_WRITE(cleanup, 1, fds[1], write_buf, sizeof(write_buf));
205
206 TEST(epoll_wait(epfd, epevs, 3, -1));
207
208 if (TEST_RETURN == -1) {
209 tst_resm(TFAIL | TTERRNO, "epoll_wait() epollio failed");
210 goto end;
211 }
212
213 if (TEST_RETURN != 2) {
214 tst_resm(TFAIL, "epoll_wait() returned %li, expected 2",
215 TEST_RETURN);
216 goto end;
217 }
218
219 if (!has_event(epevs, 2, fds[0], EPOLLIN)) {
220 dump_epevs(epevs, 2);
221 tst_resm(TFAIL, "epoll_wait() expected %d and EPOLLIN %x",
222 fds[0], EPOLLIN);
223 goto end;
224 }
225
226 if (!has_event(epevs, 2, fds[1], EPOLLOUT)) {
227 dump_epevs(epevs, 2);
228 tst_resm(TFAIL, "epoll_wait() expected %d and EPOLLOUT %x",
229 fds[1], EPOLLOUT);
230 goto end;
231 }
232
233 tst_resm(TPASS, "epoll_wait() epollio");
234
235 end:
236 SAFE_READ(cleanup, 1, fds[0], read_buf, sizeof(write_buf));
237 }
238
has_event(struct epoll_event * epevs,int epevs_len,int fd,uint32_t events)239 static int has_event(struct epoll_event *epevs, int epevs_len,
240 int fd, uint32_t events)
241 {
242 int i;
243
244 for (i = 0; i < epevs_len; i++) {
245 if ((epevs[i].data.fd == fd) && (epevs[i].events == events))
246 return 1;
247 }
248
249 return 0;
250 }
251
dump_epevs(struct epoll_event * epevs,int epevs_len)252 static void dump_epevs(struct epoll_event *epevs, int epevs_len)
253 {
254 int i;
255
256 for (i = 0; i < epevs_len; i++) {
257 tst_resm(TINFO, "epevs[%d]: epoll.data.fd %d, epoll.events %x",
258 i, epevs[i].data.fd, epevs[i].events);
259 }
260 }
261
cleanup(void)262 static void cleanup(void)
263 {
264 if (epfd > 0 && close(epfd))
265 tst_resm(TWARN | TERRNO, "failed to close epfd");
266
267 if (close(fds[0]))
268 tst_resm(TWARN | TERRNO, "failed to close fds[0]");
269
270 if (close(fds[1]))
271 tst_resm(TWARN | TERRNO, "failed to close fds[1]");
272
273 if (fds2[0] > 0 && close(fds2[0]))
274 tst_resm(TWARN | TERRNO, "failed to close fds2[0]");
275
276 if (fds2[1] > 0 && close(fds2[1]))
277 tst_resm(TWARN | TERRNO, "failed to close fds2[1]");
278 }
279