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