2
0
mirror of https://github.com/checkpoint-restore/criu synced 2025-08-30 05:48:05 +00:00

util: epoll: add processing of EPOLL{RD}HUP

Currently when we poll a file descriptor, we only process EPOLLIN events
and if a connection is closed the receiving side has no means to deal with
it.
Add a callback for EPOLL{RD}HUP events and the default implementation for
these events that removes the file descriptor from epoll and closes it.

Signed-off-by: Mike Rapoport <rppt@linux.vnet.ibm.com>
Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
This commit is contained in:
Mike Rapoport 2017-11-22 21:37:10 +02:00 committed by Andrei Vagin
parent 584123e99b
commit c6cb9d882a
2 changed files with 45 additions and 6 deletions

View File

@ -333,6 +333,14 @@ struct epoll_rfd {
* negative error code
*/
int (*read_event)(struct epoll_rfd *);
/*
* EPOLLHUP | EPOLLRDHUP notification. The remote side has
* close the connection for rfd->fd.
* @return 0 to resume polling, 1 to stop polling or a
* negative error code
*/
int (*hangup_event)(struct epoll_rfd *);
};
extern int epoll_add_rfd(int epfd, struct epoll_rfd *);

View File

@ -1324,7 +1324,7 @@ int epoll_add_rfd(int epfd, struct epoll_rfd *rfd)
{
struct epoll_event ev;
ev.events = EPOLLIN;
ev.events = EPOLLIN | EPOLLRDHUP;
ev.data.ptr = rfd;
if (epoll_ctl(epfd, EPOLL_CTL_ADD, rfd->fd, &ev) == -1) {
pr_perror("epoll_ctl failed");
@ -1344,6 +1344,24 @@ int epoll_del_rfd(int epfd, struct epoll_rfd *rfd)
return 0;
}
static int epoll_hangup_event(int epollfd, struct epoll_rfd *rfd)
{
int ret = 0;
if (rfd->hangup_event) {
ret = rfd->hangup_event(rfd);
if (ret < 0)
return ret;
}
if (epoll_del_rfd(epollfd, rfd))
return -1;
close_safe(&rfd->fd);
return ret;
}
int epoll_run_rfds(int epollfd, struct epoll_event *evs, int nr_fds, int timeout)
{
int ret, i, nr_events;
@ -1360,13 +1378,26 @@ int epoll_run_rfds(int epollfd, struct epoll_event *evs, int nr_fds, int timeout
nr_events = ret;
for (i = 0; i < nr_events; i++) {
struct epoll_rfd *rfd;
uint32_t events;
rfd = (struct epoll_rfd *)evs[i].data.ptr;
ret = rfd->read_event(rfd);
if (ret < 0)
goto out;
if (ret > 0)
have_a_break = true;
events = evs[i].events;
if (events & EPOLLIN) {
ret = rfd->read_event(rfd);
if (ret < 0)
goto out;
if (ret > 0)
have_a_break = true;
}
if (events & (EPOLLHUP | EPOLLRDHUP)) {
ret = epoll_hangup_event(epollfd, rfd);
if (ret < 0)
goto out;
if (ret > 0)
have_a_break = true;
}
}
if (have_a_break)