From: Willy Tarreau Date: Fri, 6 Jul 2012 09:16:01 +0000 (+0200) Subject: BUG/MINOR: polling: some events were not set in various pollers X-Git-Tag: v1.5-dev12~133 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=491c498d97bbe86e6ab50e4a2601767f685c09d7;p=thirdparty%2Fhaproxy.git BUG/MINOR: polling: some events were not set in various pollers fdtab[].ev was only set in ev_sepoll. Unfortunately, some I/O handling functions now rely on this, so depending on the polling mechanism, some useless operations might have been performed, such as performing a useless recv() when a HUP was reported. This is a very old issue, the flags were only added to the fdtab and not propagated into any poller. Then they were used in ev_sepoll which needed them for the cache. It is unsure whether a backport to 1.4 is appropriate or not. --- diff --git a/src/ev_epoll.c b/src/ev_epoll.c index bc7493b406..7026d56d30 100644 --- a/src/ev_epoll.c +++ b/src/ev_epoll.c @@ -242,19 +242,31 @@ REGPRM2 static void _do_poll(struct poller *p, int exp) measure_idle(); for (count = 0; count < status; count++) { + int e = epoll_events[count].events; fd = epoll_events[count].data.fd; + /* it looks complicated but gcc can optimize it away when constants + * have same values. + */ + fdtab[fd].ev &= FD_POLL_STICKY; + fdtab[fd].ev |= + ((e & EPOLLIN ) ? FD_POLL_IN : 0) | + ((e & EPOLLPRI) ? FD_POLL_PRI : 0) | + ((e & EPOLLOUT) ? FD_POLL_OUT : 0) | + ((e & EPOLLERR) ? FD_POLL_ERR : 0) | + ((e & EPOLLHUP) ? FD_POLL_HUP : 0); + if ((fd_evts[FD2OFS(fd)] >> FD2BIT(fd)) & DIR2MSK(DIR_RD)) { if (fdtab[fd].state == FD_STCLOSE) continue; - if (epoll_events[count].events & ( EPOLLIN | EPOLLERR | EPOLLHUP )) + if (fdtab[fd].ev & (FD_POLL_IN|FD_POLL_HUP|FD_POLL_ERR)) fdtab[fd].cb[DIR_RD].f(fd); } if ((fd_evts[FD2OFS(fd)] >> FD2BIT(fd)) & DIR2MSK(DIR_WR)) { if (fdtab[fd].state == FD_STCLOSE) continue; - if (epoll_events[count].events & ( EPOLLOUT | EPOLLERR | EPOLLHUP )) + if (fdtab[fd].ev & (FD_POLL_OUT|FD_POLL_ERR|FD_POLL_HUP)) fdtab[fd].cb[DIR_WR].f(fd); } } diff --git a/src/ev_kqueue.c b/src/ev_kqueue.c index b43533ab5c..df4f920b75 100644 --- a/src/ev_kqueue.c +++ b/src/ev_kqueue.c @@ -142,12 +142,14 @@ REGPRM2 static void _do_poll(struct poller *p, int exp) if (FD_ISSET(fd, fd_evts[DIR_RD])) { if (fdtab[fd].state == FD_STCLOSE) continue; + fdtab[fd].ev |= FD_POLL_IN; fdtab[fd].cb[DIR_RD].f(fd); } } else if (kev[count].filter == EVFILT_WRITE) { if (FD_ISSET(fd, fd_evts[DIR_WR])) { if (fdtab[fd].state == FD_STCLOSE) continue; + fdtab[fd].ev |= FD_POLL_OUT; fdtab[fd].cb[DIR_WR].f(fd); } } diff --git a/src/ev_poll.c b/src/ev_poll.c index ec18863b44..8f2e1d986e 100644 --- a/src/ev_poll.c +++ b/src/ev_poll.c @@ -143,25 +143,33 @@ REGPRM2 static void _do_poll(struct poller *p, int exp) measure_idle(); for (count = 0; status > 0 && count < nbfd; count++) { + int e = poll_events[count].revents; fd = poll_events[count].fd; - if (!(poll_events[count].revents & ( POLLOUT | POLLIN | POLLERR | POLLHUP ))) + if (!(e & ( POLLOUT | POLLIN | POLLERR | POLLHUP ))) continue; + fdtab[fd].ev &= FD_POLL_STICKY; + fdtab[fd].ev |= + ((e & POLLIN ) ? FD_POLL_IN : 0) | + ((e & POLLOUT) ? FD_POLL_OUT : 0) | + ((e & POLLERR) ? FD_POLL_ERR : 0) | + ((e & POLLHUP) ? FD_POLL_HUP : 0); + /* ok, we found one active fd */ status--; if (FD_ISSET(fd, fd_evts[DIR_RD])) { if (fdtab[fd].state == FD_STCLOSE) continue; - if (poll_events[count].revents & ( POLLIN | POLLERR | POLLHUP )) + if (fdtab[fd].ev & (FD_POLL_IN|FD_POLL_HUP|FD_POLL_ERR)) fdtab[fd].cb[DIR_RD].f(fd); } if (FD_ISSET(fd, fd_evts[DIR_WR])) { if (fdtab[fd].state == FD_STCLOSE) continue; - if (poll_events[count].revents & ( POLLOUT | POLLERR | POLLHUP )) + if (fdtab[fd].ev & (FD_POLL_OUT|FD_POLL_ERR|FD_POLL_HUP)) fdtab[fd].cb[DIR_WR].f(fd); } } diff --git a/src/ev_select.c b/src/ev_select.c index 0924e3fda9..72eca0b3f4 100644 --- a/src/ev_select.c +++ b/src/ev_select.c @@ -149,12 +149,14 @@ REGPRM2 static void _do_poll(struct poller *p, int exp) if (FD_ISSET(fd, tmp_evts[DIR_RD])) { if (fdtab[fd].state == FD_STCLOSE) continue; + fdtab[fd].ev |= FD_POLL_IN; fdtab[fd].cb[DIR_RD].f(fd); } if (FD_ISSET(fd, tmp_evts[DIR_WR])) { if (fdtab[fd].state == FD_STCLOSE) continue; + fdtab[fd].ev |= FD_POLL_OUT; fdtab[fd].cb[DIR_WR].f(fd); } } diff --git a/src/ev_sepoll.c b/src/ev_sepoll.c index c8444bee3c..b5048157bd 100644 --- a/src/ev_sepoll.c +++ b/src/ev_sepoll.c @@ -402,13 +402,13 @@ REGPRM2 static void _do_poll(struct poller *p, int exp) * have same values. */ fdtab[fd].ev &= FD_POLL_STICKY; - fdtab[fd].ev |= + fdtab[fd].ev |= ((e & EPOLLIN ) ? FD_POLL_IN : 0) | ((e & EPOLLPRI) ? FD_POLL_PRI : 0) | ((e & EPOLLOUT) ? FD_POLL_OUT : 0) | ((e & EPOLLERR) ? FD_POLL_ERR : 0) | ((e & EPOLLHUP) ? FD_POLL_HUP : 0); - + if ((fdtab[fd].spec.e & FD_EV_MASK_R) == FD_EV_WAIT_R) { if (fdtab[fd].state == FD_STCLOSE || fdtab[fd].state == FD_STERROR) continue;