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 
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 
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 
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 
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 
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 
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 
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 
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 
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