From fb8983f21b69f3341fc5a4076ab3c98887d16463 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Sun, 3 Jun 2007 16:40:44 +0200 Subject: [PATCH] [BUG] the epoll FD must not be shared between processes Recreate the epoll file descriptor after a fork(). It will ensure that all processes will not share their epoll_fd. Some side effects were encountered because of this, such as epoll_wait() returning an FD which was previously deleted, in multi-process mode. --- src/ev_epoll.c | 16 ++++++++++++++++ src/ev_sepoll.c | 16 ++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/src/ev_epoll.c b/src/ev_epoll.c index d313d56906..9dccb3526c 100644 --- a/src/ev_epoll.c +++ b/src/ev_epoll.c @@ -354,6 +354,21 @@ REGPRM1 static int _do_test(struct poller *p) return 1; } +/* + * Recreate the epoll file descriptor after a fork(). Returns 1 if OK, + * otherwise 0. It will ensure that all processes will not share their + * epoll_fd. Some side effects were encountered because of this, such + * as epoll_wait() returning an FD which was previously deleted. + */ +REGPRM1 static int _do_fork(struct poller *p) +{ + close(epoll_fd); + epoll_fd = epoll_create(global.maxsock + 1); + if (epoll_fd < 0) + return 0; + return 1; +} + /* * It is a constructor, which means that it will automatically be called before * main(). This is GCC-specific but it works at least since 2.95. @@ -376,6 +391,7 @@ static void _do_register(void) p->init = _do_init; p->term = _do_term; p->poll = _do_poll; + p->fork = _do_fork; p->is_set = __fd_is_set; p->cond_s = p->set = __fd_set; diff --git a/src/ev_sepoll.c b/src/ev_sepoll.c index 3e25866f8e..d304c12900 100644 --- a/src/ev_sepoll.c +++ b/src/ev_sepoll.c @@ -504,6 +504,21 @@ REGPRM1 static int _do_test(struct poller *p) return 1; } +/* + * Recreate the epoll file descriptor after a fork(). Returns 1 if OK, + * otherwise 0. It will ensure that all processes will not share their + * epoll_fd. Some side effects were encountered because of this, such + * as epoll_wait() returning an FD which was previously deleted. + */ +REGPRM1 static int _do_fork(struct poller *p) +{ + close(epoll_fd); + epoll_fd = epoll_create(global.maxsock + 1); + if (epoll_fd < 0) + return 0; + return 1; +} + /* * It is a constructor, which means that it will automatically be called before * main(). This is GCC-specific but it works at least since 2.95. @@ -526,6 +541,7 @@ static void _do_register(void) p->init = _do_init; p->term = _do_term; p->poll = _do_poll; + p->fork = _do_fork; p->is_set = __fd_is_set; p->cond_s = p->set = __fd_set; -- 2.47.2