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