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