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