[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