/*
* Copyright (c) 2016 Fujitsu Ltd.
* Author: Xiao Yang <yangx.jy@cn.fujitsu.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it would be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU General Public License
* alone with this program.
*/
/*
* Test Name: epoll_ctl01.c
*
* Description:
* Testcase to check the basic functionality of the epoll_ctl(2).
* 1) when epoll_ctl(2) succeeds to register fd on the epoll instance and
* associates event with fd, epoll_wait(2) will get registered fd and
* event correctly.
* 2) when epoll_ctl(2) succeeds to chage event which is related to fd,
* epoll_wait(2) will get chaged event correctly.
* 3) when epoll_ctl(2) succeeds to deregister fd from the epoll instance
* epoll_wait(2) won't get deregistered fd and event.
*
*/
#include <sys/epoll.h>
#include <poll.h>
#include <string.h>
#include <errno.h>
#include "tst_test.h"
static int epfd;
static int fd[2];
static struct epoll_event events[3] = {
{.events = EPOLLIN},
{.events = EPOLLOUT},
{.events = EPOLLIN}
};
static void setup(void)
{
epfd = epoll_create(2);
if (epfd == -1)
tst_brk(TBROK | TERRNO, "fail to create epoll instance");
SAFE_PIPE(fd);
events[0].data.fd = fd[0];
events[1].data.fd = fd[1];
events[2].data.fd = fd[1];
}
static void cleanup(void)
{
if (epfd > 0)
SAFE_CLOSE(epfd);
if (fd[0] > 0)
SAFE_CLOSE(fd[0]);
if (fd[1] > 0)
SAFE_CLOSE(fd[1]);
}
static int has_event(struct epoll_event *epvs, int len,
int fd, unsigned int events)
{
int i;
for (i = 0; i < len; i++) {
if ((epvs[i].data.fd == fd) && (epvs[i].events == events))
return 1;
}
return 0;
}
static void check_epoll_ctl(int opt, int exp_num)
{
int res;
unsigned int events;
char write_buf[] = "test";
char read_buf[sizeof(write_buf)];
struct epoll_event res_evs[2];
events = EPOLLIN;
if (exp_num == 2)
events |= EPOLLOUT;
SAFE_WRITE(1, fd[1], write_buf, sizeof(write_buf));
while (events) {
int events_matched = 0;
bzero(res_evs, sizeof(res_evs));
res = epoll_wait(epfd, res_evs, 2, -1);
if (res <= 0) {
tst_res(TFAIL | TERRNO, "epoll_wait() returned %i",
res);
goto end;
}
if ((events & EPOLLIN) &&
has_event(res_evs, 2, fd[0], EPOLLIN)) {
events_matched++;
events &= ~EPOLLIN;
}
if ((events & EPOLLOUT) &&
has_event(res_evs, 2, fd[1], EPOLLOUT)) {
events_matched++;
events &= ~EPOLLOUT;
}
if (res != events_matched) {
tst_res(TFAIL,
"epoll_wait() returned unexpected events");
goto end;
}
}
tst_res(TPASS, "epoll_ctl() succeeds with op %i", opt);
end:
SAFE_READ(1, fd[0], read_buf, sizeof(write_buf));
}
static void opera_epoll_ctl(int opt, int fd, struct epoll_event *epvs)
{
TEST(epoll_ctl(epfd, opt, fd, epvs));
if (TEST_RETURN == -1)
tst_brk(TBROK | TTERRNO, "epoll_ctl() fails with op %i", opt);
}
static void verify_epoll_ctl(void)
{
opera_epoll_ctl(EPOLL_CTL_ADD, fd[0], &events[0]);
opera_epoll_ctl(EPOLL_CTL_ADD, fd[1], &events[2]);
check_epoll_ctl(EPOLL_CTL_ADD, 1);
opera_epoll_ctl(EPOLL_CTL_MOD, fd[1], &events[1]);
check_epoll_ctl(EPOLL_CTL_MOD, 2);
opera_epoll_ctl(EPOLL_CTL_DEL, fd[1], &events[1]);
check_epoll_ctl(EPOLL_CTL_DEL, 1);
opera_epoll_ctl(EPOLL_CTL_DEL, fd[0], &events[0]);
}
static struct tst_test test = {
.setup = setup,
.cleanup = cleanup,
.test_all = verify_epoll_ctl,
};