mirror of
https://github.com/checkpoint-restore/criu
synced 2025-08-31 06:15:24 +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:
committed by
Andrei Vagin
parent
584123e99b
commit
c6cb9d882a
@@ -333,6 +333,14 @@ struct epoll_rfd {
|
|||||||
* negative error code
|
* negative error code
|
||||||
*/
|
*/
|
||||||
int (*read_event)(struct epoll_rfd *);
|
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 *);
|
extern int epoll_add_rfd(int epfd, struct epoll_rfd *);
|
||||||
|
33
criu/util.c
33
criu/util.c
@@ -1324,7 +1324,7 @@ int epoll_add_rfd(int epfd, struct epoll_rfd *rfd)
|
|||||||
{
|
{
|
||||||
struct epoll_event ev;
|
struct epoll_event ev;
|
||||||
|
|
||||||
ev.events = EPOLLIN;
|
ev.events = EPOLLIN | EPOLLRDHUP;
|
||||||
ev.data.ptr = rfd;
|
ev.data.ptr = rfd;
|
||||||
if (epoll_ctl(epfd, EPOLL_CTL_ADD, rfd->fd, &ev) == -1) {
|
if (epoll_ctl(epfd, EPOLL_CTL_ADD, rfd->fd, &ev) == -1) {
|
||||||
pr_perror("epoll_ctl failed");
|
pr_perror("epoll_ctl failed");
|
||||||
@@ -1344,6 +1344,24 @@ int epoll_del_rfd(int epfd, struct epoll_rfd *rfd)
|
|||||||
return 0;
|
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 epoll_run_rfds(int epollfd, struct epoll_event *evs, int nr_fds, int timeout)
|
||||||
{
|
{
|
||||||
int ret, i, nr_events;
|
int ret, i, nr_events;
|
||||||
@@ -1360,8 +1378,12 @@ int epoll_run_rfds(int epollfd, struct epoll_event *evs, int nr_fds, int timeout
|
|||||||
nr_events = ret;
|
nr_events = ret;
|
||||||
for (i = 0; i < nr_events; i++) {
|
for (i = 0; i < nr_events; i++) {
|
||||||
struct epoll_rfd *rfd;
|
struct epoll_rfd *rfd;
|
||||||
|
uint32_t events;
|
||||||
|
|
||||||
rfd = (struct epoll_rfd *)evs[i].data.ptr;
|
rfd = (struct epoll_rfd *)evs[i].data.ptr;
|
||||||
|
events = evs[i].events;
|
||||||
|
|
||||||
|
if (events & EPOLLIN) {
|
||||||
ret = rfd->read_event(rfd);
|
ret = rfd->read_event(rfd);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out;
|
goto out;
|
||||||
@@ -1369,6 +1391,15 @@ int epoll_run_rfds(int epollfd, struct epoll_event *evs, int nr_fds, int timeout
|
|||||||
have_a_break = true;
|
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)
|
if (have_a_break)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user