1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
2f08c3bdfSopenharmony_ci/*
3f08c3bdfSopenharmony_ci * Copyright (c) 2016 Fujitsu Ltd.
4f08c3bdfSopenharmony_ci * Author: Xiao Yang <yangx.jy@cn.fujitsu.com>
5f08c3bdfSopenharmony_ci */
6f08c3bdfSopenharmony_ci
7f08c3bdfSopenharmony_ci/*\
8f08c3bdfSopenharmony_ci * [Description]
9f08c3bdfSopenharmony_ci *
10f08c3bdfSopenharmony_ci * Check the basic functionality of the epoll_ctl:
11f08c3bdfSopenharmony_ci *
12f08c3bdfSopenharmony_ci * - When epoll_ctl succeeds to register fd on the epoll instance and associates
13f08c3bdfSopenharmony_ci * event with fd, epoll_wait will get registered fd and event correctly.
14f08c3bdfSopenharmony_ci * - When epoll_ctl succeeds to change event which is related to fd, epoll_wait
15f08c3bdfSopenharmony_ci * will get changed event correctly.
16f08c3bdfSopenharmony_ci * - When epoll_ctl succeeds to deregister fd from the epoll instance epoll_wait
17f08c3bdfSopenharmony_ci * won't get deregistered fd and event.
18f08c3bdfSopenharmony_ci */
19f08c3bdfSopenharmony_ci
20f08c3bdfSopenharmony_ci#include <poll.h>
21f08c3bdfSopenharmony_ci#include <sys/epoll.h>
22f08c3bdfSopenharmony_ci
23f08c3bdfSopenharmony_ci#include "tst_test.h"
24f08c3bdfSopenharmony_ci
25f08c3bdfSopenharmony_cistatic int epfd;
26f08c3bdfSopenharmony_cistatic int fd[2];
27f08c3bdfSopenharmony_ci
28f08c3bdfSopenharmony_cistatic struct epoll_event events[3] = {
29f08c3bdfSopenharmony_ci	{.events = EPOLLIN},
30f08c3bdfSopenharmony_ci	{.events = EPOLLOUT},
31f08c3bdfSopenharmony_ci	{.events = EPOLLIN}
32f08c3bdfSopenharmony_ci};
33f08c3bdfSopenharmony_ci
34f08c3bdfSopenharmony_cistatic void setup(void)
35f08c3bdfSopenharmony_ci{
36f08c3bdfSopenharmony_ci	epfd = epoll_create(2);
37f08c3bdfSopenharmony_ci	if (epfd == -1)
38f08c3bdfSopenharmony_ci		tst_brk(TBROK | TERRNO, "fail to create epoll instance");
39f08c3bdfSopenharmony_ci
40f08c3bdfSopenharmony_ci	SAFE_PIPE(fd);
41f08c3bdfSopenharmony_ci
42f08c3bdfSopenharmony_ci	events[0].data.fd = fd[0];
43f08c3bdfSopenharmony_ci	events[1].data.fd = fd[1];
44f08c3bdfSopenharmony_ci	events[2].data.fd = fd[1];
45f08c3bdfSopenharmony_ci}
46f08c3bdfSopenharmony_ci
47f08c3bdfSopenharmony_cistatic void cleanup(void)
48f08c3bdfSopenharmony_ci{
49f08c3bdfSopenharmony_ci	if (epfd > 0)
50f08c3bdfSopenharmony_ci		SAFE_CLOSE(epfd);
51f08c3bdfSopenharmony_ci
52f08c3bdfSopenharmony_ci	if (fd[0] > 0)
53f08c3bdfSopenharmony_ci		SAFE_CLOSE(fd[0]);
54f08c3bdfSopenharmony_ci
55f08c3bdfSopenharmony_ci	if (fd[1] > 0)
56f08c3bdfSopenharmony_ci		SAFE_CLOSE(fd[1]);
57f08c3bdfSopenharmony_ci}
58f08c3bdfSopenharmony_ci
59f08c3bdfSopenharmony_cistatic int has_event(struct epoll_event *epvs, int len,
60f08c3bdfSopenharmony_ci	int fd, unsigned int events)
61f08c3bdfSopenharmony_ci{
62f08c3bdfSopenharmony_ci	int i;
63f08c3bdfSopenharmony_ci
64f08c3bdfSopenharmony_ci	for (i = 0; i < len; i++) {
65f08c3bdfSopenharmony_ci		if ((epvs[i].data.fd == fd) && (epvs[i].events == events))
66f08c3bdfSopenharmony_ci			return 1;
67f08c3bdfSopenharmony_ci	}
68f08c3bdfSopenharmony_ci
69f08c3bdfSopenharmony_ci	return 0;
70f08c3bdfSopenharmony_ci}
71f08c3bdfSopenharmony_ci
72f08c3bdfSopenharmony_cistatic void check_epoll_ctl(int opt, int exp_num)
73f08c3bdfSopenharmony_ci{
74f08c3bdfSopenharmony_ci	int res;
75f08c3bdfSopenharmony_ci	unsigned int events;
76f08c3bdfSopenharmony_ci	char write_buf[] = "test";
77f08c3bdfSopenharmony_ci	char read_buf[sizeof(write_buf)];
78f08c3bdfSopenharmony_ci	struct epoll_event res_evs[2];
79f08c3bdfSopenharmony_ci
80f08c3bdfSopenharmony_ci	events = EPOLLIN;
81f08c3bdfSopenharmony_ci	if (exp_num == 2)
82f08c3bdfSopenharmony_ci		events |= EPOLLOUT;
83f08c3bdfSopenharmony_ci
84f08c3bdfSopenharmony_ci	SAFE_WRITE(SAFE_WRITE_ALL, fd[1], write_buf, sizeof(write_buf));
85f08c3bdfSopenharmony_ci
86f08c3bdfSopenharmony_ci	while (events) {
87f08c3bdfSopenharmony_ci		int events_matched = 0;
88f08c3bdfSopenharmony_ci
89f08c3bdfSopenharmony_ci		memset(res_evs, 0, sizeof(res_evs));
90f08c3bdfSopenharmony_ci		res = epoll_wait(epfd, res_evs, 2, -1);
91f08c3bdfSopenharmony_ci
92f08c3bdfSopenharmony_ci		if (res <= 0) {
93f08c3bdfSopenharmony_ci			tst_res(TFAIL | TERRNO, "epoll_wait() returned %i",
94f08c3bdfSopenharmony_ci				res);
95f08c3bdfSopenharmony_ci			goto end;
96f08c3bdfSopenharmony_ci		}
97f08c3bdfSopenharmony_ci
98f08c3bdfSopenharmony_ci		if ((events & EPOLLIN) &&
99f08c3bdfSopenharmony_ci		    has_event(res_evs, 2, fd[0], EPOLLIN)) {
100f08c3bdfSopenharmony_ci			events_matched++;
101f08c3bdfSopenharmony_ci			events &= ~EPOLLIN;
102f08c3bdfSopenharmony_ci		}
103f08c3bdfSopenharmony_ci
104f08c3bdfSopenharmony_ci		if ((events & EPOLLOUT) &&
105f08c3bdfSopenharmony_ci		    has_event(res_evs, 2, fd[1], EPOLLOUT)) {
106f08c3bdfSopenharmony_ci			events_matched++;
107f08c3bdfSopenharmony_ci			events &= ~EPOLLOUT;
108f08c3bdfSopenharmony_ci		}
109f08c3bdfSopenharmony_ci
110f08c3bdfSopenharmony_ci		if (res != events_matched) {
111f08c3bdfSopenharmony_ci			tst_res(TFAIL,
112f08c3bdfSopenharmony_ci				"epoll_wait() returned unexpected events");
113f08c3bdfSopenharmony_ci			goto end;
114f08c3bdfSopenharmony_ci		}
115f08c3bdfSopenharmony_ci	}
116f08c3bdfSopenharmony_ci
117f08c3bdfSopenharmony_ci	tst_res(TPASS, "epoll_ctl() succeeds with op %i", opt);
118f08c3bdfSopenharmony_ci
119f08c3bdfSopenharmony_ciend:
120f08c3bdfSopenharmony_ci	SAFE_READ(1, fd[0], read_buf, sizeof(write_buf));
121f08c3bdfSopenharmony_ci}
122f08c3bdfSopenharmony_ci
123f08c3bdfSopenharmony_cistatic void opera_epoll_ctl(int opt, int fd, struct epoll_event *epvs)
124f08c3bdfSopenharmony_ci{
125f08c3bdfSopenharmony_ci	TEST(epoll_ctl(epfd, opt, fd, epvs));
126f08c3bdfSopenharmony_ci	if (TST_RET == -1)
127f08c3bdfSopenharmony_ci		tst_brk(TBROK | TTERRNO, "epoll_ctl() fails with op %i", opt);
128f08c3bdfSopenharmony_ci}
129f08c3bdfSopenharmony_ci
130f08c3bdfSopenharmony_cistatic void verify_epoll_ctl(void)
131f08c3bdfSopenharmony_ci{
132f08c3bdfSopenharmony_ci	opera_epoll_ctl(EPOLL_CTL_ADD, fd[0], &events[0]);
133f08c3bdfSopenharmony_ci	opera_epoll_ctl(EPOLL_CTL_ADD, fd[1], &events[2]);
134f08c3bdfSopenharmony_ci	check_epoll_ctl(EPOLL_CTL_ADD, 1);
135f08c3bdfSopenharmony_ci	opera_epoll_ctl(EPOLL_CTL_MOD, fd[1], &events[1]);
136f08c3bdfSopenharmony_ci	check_epoll_ctl(EPOLL_CTL_MOD, 2);
137f08c3bdfSopenharmony_ci	opera_epoll_ctl(EPOLL_CTL_DEL, fd[1], &events[1]);
138f08c3bdfSopenharmony_ci	check_epoll_ctl(EPOLL_CTL_DEL, 1);
139f08c3bdfSopenharmony_ci	opera_epoll_ctl(EPOLL_CTL_DEL, fd[0], &events[0]);
140f08c3bdfSopenharmony_ci}
141f08c3bdfSopenharmony_ci
142f08c3bdfSopenharmony_cistatic struct tst_test test = {
143f08c3bdfSopenharmony_ci	.setup = setup,
144f08c3bdfSopenharmony_ci	.cleanup = cleanup,
145f08c3bdfSopenharmony_ci	.test_all = verify_epoll_ctl,
146f08c3bdfSopenharmony_ci};
147