[CRIU] [PATCH 3/5] util: epoll: add processing of EPOLL{RD}HUP
Mike Rapoport
rppt at linux.vnet.ibm.com
Wed Nov 22 22:37:10 MSK 2017
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 at linux.vnet.ibm.com>
---
criu/include/util.h | 8 ++++++++
criu/util.c | 43 +++++++++++++++++++++++++++++++++++++------
2 files changed, 45 insertions(+), 6 deletions(-)
diff --git a/criu/include/util.h b/criu/include/util.h
index cf24ed1..c40b0c6 100644
--- a/criu/include/util.h
+++ b/criu/include/util.h
@@ -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 *);
diff --git a/criu/util.c b/criu/util.c
index 3f490ea..eb5ed73 100644
--- a/criu/util.c
+++ b/criu/util.c
@@ -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)
--
2.7.4
More information about the CRIU
mailing list