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 "tst_test.h"
32
33 static int write_size, epfd, fds[2];
34
get_writesize(void)35 static int get_writesize(void)
36 {
37 int nfd, write_size = 0;
38 char buf[4096];
39 struct pollfd pfd[] = {
40 {.fd = fds[1], .events = POLLOUT},
41 };
42
43 memset(buf, 'a', sizeof(buf));
44
45 do {
46 write_size += SAFE_WRITE(0, fds[1], buf, sizeof(buf));
47 nfd = poll(pfd, 1, 1);
48 if (nfd == -1)
49 tst_brk(TBROK | TERRNO, "poll() failed");
50 } while (nfd > 0);
51
52 char read_buf[write_size];
53
54 SAFE_READ(1, fds[0], read_buf, sizeof(read_buf));
55
56 tst_res(TINFO, "Pipe buffer size is %i bytes", write_size);
57
58 return write_size;
59 }
60
setup(void)61 static void setup(void)
62 {
63 static struct epoll_event epevs[2] = {
64 {.events = EPOLLIN},
65 {.events = EPOLLOUT},
66 };
67
68 SAFE_PIPE(fds);
69
70 epevs[0].data.fd = fds[0];
71 epevs[1].data.fd = fds[1];
72
73 write_size = get_writesize();
74
75 epfd = epoll_create(3);
76 if (epfd == -1)
77 tst_brk(TBROK | TERRNO, "epoll_create() failed");
78
79 if (epoll_ctl(epfd, EPOLL_CTL_ADD, fds[0], &epevs[0]) ||
80 epoll_ctl(epfd, EPOLL_CTL_ADD, fds[1], &epevs[1])) {
81 tst_brk(TBROK | TERRNO, "epoll_ctl() failed");
82 }
83 }
84
has_event(struct epoll_event * epevs,int epevs_len,int fd,uint32_t events)85 static int has_event(struct epoll_event *epevs, int epevs_len,
86 int fd, uint32_t events)
87 {
88 int i;
89
90 for (i = 0; i < epevs_len; i++) {
91 if ((epevs[i].data.fd == fd) && (epevs[i].events == events))
92 return 1;
93 }
94
95 return 0;
96 }
97
dump_epevs(struct epoll_event * epevs,int epevs_len)98 static void dump_epevs(struct epoll_event *epevs, int epevs_len)
99 {
100 int i;
101
102 for (i = 0; i < epevs_len; i++) {
103 tst_res(TINFO, "epevs[%d]: epoll.data.fd %d, epoll.events %x",
104 i, epevs[i].data.fd, epevs[i].events);
105 }
106 }
107
verify_epollout(void)108 static void verify_epollout(void)
109 {
110 struct epoll_event ret_evs = {.events = 0, .data.fd = 0};
111
112 TEST(epoll_wait(epfd, &ret_evs, 1, -1));
113
114 if (TEST_RETURN == -1) {
115 tst_res(TFAIL | TTERRNO, "epoll_wait() epollout failed");
116 return;
117 }
118
119 if (TEST_RETURN != 1) {
120 tst_res(TFAIL, "epoll_wait() returned %li, expected 1",
121 TEST_RETURN);
122 return;
123 }
124
125 if (ret_evs.data.fd != fds[1]) {
126 tst_res(TFAIL, "epoll.data.fd %i, expected %i",
127 ret_evs.data.fd, fds[1]);
128 return;
129 }
130
131 if (ret_evs.events != EPOLLOUT) {
132 tst_res(TFAIL, "epoll.events %x, expected EPOLLOUT %x",
133 ret_evs.events, EPOLLOUT);
134 return;
135 }
136
137 tst_res(TPASS, "epoll_wait() epollout");
138 }
139
verify_epollin(void)140 static void verify_epollin(void)
141 {
142 char write_buf[write_size];
143 char read_buf[sizeof(write_buf)];
144 struct epoll_event ret_evs = {.events = 0, .data.fd = 0};
145
146 memset(write_buf, 'a', sizeof(write_buf));
147
148 SAFE_WRITE(1, fds[1], write_buf, sizeof(write_buf));
149
150 TEST(epoll_wait(epfd, &ret_evs, 1, -1));
151
152 if (TEST_RETURN == -1) {
153 tst_res(TFAIL | TTERRNO, "epoll_wait() epollin failed");
154 goto end;
155 }
156
157 if (TEST_RETURN != 1) {
158 tst_res(TFAIL, "epoll_wait() returned %li, expected 1",
159 TEST_RETURN);
160 goto end;
161 }
162
163 if (ret_evs.data.fd != fds[0]) {
164 tst_res(TFAIL, "epoll.data.fd %i, expected %i",
165 ret_evs.data.fd, fds[0]);
166 goto end;
167 }
168
169 if (ret_evs.events != EPOLLIN) {
170 tst_res(TFAIL, "epoll.events %x, expected EPOLLIN %x",
171 ret_evs.events, EPOLLIN);
172 goto end;
173 }
174
175 tst_res(TPASS, "epoll_wait() epollin");
176
177 end:
178 SAFE_READ(1, fds[0], read_buf, sizeof(write_buf));
179 }
180
verify_epollio(void)181 static void verify_epollio(void)
182 {
183 char write_buf[] = "Testing";
184 char read_buf[sizeof(write_buf)];
185 uint32_t events = EPOLLIN | EPOLLOUT;
186 struct epoll_event ret_evs[2];
187
188 SAFE_WRITE(1, fds[1], write_buf, sizeof(write_buf));
189
190 while (events) {
191 int events_matched = 0;
192
193 bzero(ret_evs, sizeof(ret_evs));
194 TEST(epoll_wait(epfd, ret_evs, 2, -1));
195
196 if (TEST_RETURN <= 0) {
197 tst_res(TFAIL | TTERRNO, "epoll_wait() returned %li",
198 TEST_RETURN);
199 goto end;
200 }
201
202 if ((events & EPOLLIN) &&
203 has_event(ret_evs, 2, fds[0], EPOLLIN)) {
204 events_matched++;
205 events &= ~EPOLLIN;
206 }
207
208 if ((events & EPOLLOUT) &&
209 has_event(ret_evs, 2, fds[1], EPOLLOUT)) {
210 events_matched++;
211 events &= ~EPOLLOUT;
212 }
213
214 if (TEST_RETURN != events_matched) {
215 tst_res(TFAIL,
216 "epoll_wait() returned unexpected events");
217 dump_epevs(ret_evs, 2);
218 goto end;
219 }
220 }
221
222 tst_res(TPASS, "epoll_wait() epollio");
223
224 end:
225 SAFE_READ(1, fds[0], read_buf, sizeof(write_buf));
226 }
227
cleanup(void)228 static void cleanup(void)
229 {
230 if (epfd > 0)
231 SAFE_CLOSE(epfd);
232
233 if (fds[0]) {
234 SAFE_CLOSE(fds[0]);
235 SAFE_CLOSE(fds[1]);
236 }
237 }
238
do_test(unsigned int n)239 static void do_test(unsigned int n)
240 {
241 switch (n) {
242 case 0:
243 verify_epollout();
244 break;
245 case 1:
246 verify_epollin();
247 break;
248 case 2:
249 verify_epollio();
250 break;
251 }
252 }
253
254 static struct tst_test test = {
255 .setup = setup,
256 .cleanup = cleanup,
257 .test = do_test,
258 .tcnt = 3,
259 };
260