diff --git a/include/proto/fd.h b/include/proto/fd.h index e3b0b2b2f..3ee71a5a1 100644 --- a/include/proto/fd.h +++ b/include/proto/fd.h @@ -318,20 +318,32 @@ static inline void fd_want_send(int fd) updt_fd_polling(fd); } -/* Update events seen for FD and its state if needed. This should be called - * by the poller to set FD_POLL_* flags. */ -static inline void fd_update_events(int fd, int evts) +/* Update events seen for FD and its state if needed. This should be + * called by the poller, passing FD_EV_*_{R,W,RW} in . FD_EV_ERR_* + * doesn't need to also pass FD_EV_SHUT_*, it's implied. ERR and SHUT are + * allowed to be reported regardless of R/W readiness. + */ +static inline void fd_update_events(int fd, unsigned char evts) { unsigned long locked = atleast2(fdtab[fd].thread_mask); unsigned char old, new; + int new_flags; + + new_flags = + ((evts & FD_EV_READY_R) ? FD_POLL_IN : 0) | + ((evts & FD_EV_READY_W) ? FD_POLL_OUT : 0) | + ((evts & FD_EV_SHUT_R) ? FD_POLL_HUP : 0) | + ((evts & FD_EV_SHUT_W) ? FD_POLL_ERR : 0) | + ((evts & FD_EV_ERR_R) ? FD_POLL_ERR : 0) | + ((evts & FD_EV_ERR_W) ? FD_POLL_ERR : 0); old = fdtab[fd].ev; - new = (old & FD_POLL_STICKY) | evts; + new = (old & FD_POLL_STICKY) | new_flags; if (unlikely(locked)) { /* Locked FDs (those with more than 2 threads) are atomically updated */ while (unlikely(new != old && !_HA_ATOMIC_CAS(&fdtab[fd].ev, &old, new))) - new = (old & FD_POLL_STICKY) | evts; + new = (old & FD_POLL_STICKY) | new_flags; } else { if (new != old) fdtab[fd].ev = new; diff --git a/src/ev_epoll.c b/src/ev_epoll.c index 5172aecec..dc156e58f 100644 --- a/src/ev_epoll.c +++ b/src/ev_epoll.c @@ -218,27 +218,15 @@ REGPRM3 static void _do_poll(struct poller *p, int exp, int wake) continue; } - /* it looks complicated but gcc can optimize it away when constants - * have same values... In fact it depends on gcc :-( - */ - if (EPOLLIN == FD_POLL_IN && EPOLLOUT == FD_POLL_OUT && - EPOLLPRI == FD_POLL_PRI && EPOLLERR == FD_POLL_ERR && - EPOLLHUP == FD_POLL_HUP) { - n = e & (EPOLLIN|EPOLLOUT|EPOLLPRI|EPOLLERR|EPOLLHUP); - } - else { - n = ((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); - } + n = ((e & EPOLLIN) ? FD_EV_READY_R : 0) | + ((e & EPOLLOUT) ? FD_EV_READY_W : 0) | + ((e & EPOLLRDHUP) ? FD_EV_SHUT_R : 0) | + ((e & EPOLLHUP) ? FD_EV_SHUT_RW : 0) | + ((e & EPOLLERR) ? FD_EV_ERR_RW : 0); - /* always remap RDHUP to HUP as they're used similarly */ - if (e & EPOLLRDHUP) { + if ((e & EPOLLRDHUP) && !(cur_poller.flags & HAP_POLL_F_RDHUP)) _HA_ATOMIC_OR(&cur_poller.flags, HAP_POLL_F_RDHUP); - n |= FD_POLL_HUP; - } + fd_update_events(fd, n); } /* the caller will take care of cached events */ diff --git a/src/ev_evports.c b/src/ev_evports.c index 46edb6962..e734b220e 100644 --- a/src/ev_evports.c +++ b/src/ev_evports.c @@ -241,14 +241,10 @@ REGPRM3 static void _do_poll(struct poller *p, int exp, int wake) /* * Set bits based on the events we received from the port: */ - if (events & POLLIN) - n |= FD_POLL_IN; - if (events & POLLOUT) - n |= FD_POLL_OUT; - if (events & POLLERR) - n |= FD_POLL_ERR; - if (events & POLLHUP) - n |= FD_POLL_HUP; + n = ((e & POLLIN) ? FD_EV_READY_R : 0) | + ((e & POLLOUT) ? FD_EV_READY_W : 0) | + ((e & POLLHUP) ? FD_EV_SHUT_RW : 0) | + ((e & POLLERR) ? FD_EV_ERR_RW : 0); /* * Call connection processing callbacks. Note that it's diff --git a/src/ev_kqueue.c b/src/ev_kqueue.c index 191ddce56..8f0b7c907 100644 --- a/src/ev_kqueue.c +++ b/src/ev_kqueue.c @@ -196,16 +196,16 @@ REGPRM3 static void _do_poll(struct poller *p, int exp, int wake) continue; } - if (kev[count].filter == EVFILT_READ) { + if (kev[count].filter == EVFILT_READ) { if (kev[count].data) - n |= FD_POLL_IN; + n |= FD_EV_READY_R; if (kev[count].flags & EV_EOF) - n |= FD_POLL_HUP; + n |= FD_EV_SHUT_R; } - else if (kev[count].filter == EVFILT_WRITE) { - n |= FD_POLL_OUT; + else if (kev[count].filter == EVFILT_WRITE) { + n |= FD_EV_READY_W; if (kev[count].flags & EV_EOF) - n |= FD_POLL_ERR; + n |= FD_EV_ERR_RW; } fd_update_events(fd, n); diff --git a/src/ev_poll.c b/src/ev_poll.c index 6c5de9bea..7655ca559 100644 --- a/src/ev_poll.c +++ b/src/ev_poll.c @@ -231,25 +231,15 @@ REGPRM3 static void _do_poll(struct poller *p, int exp, int wake) continue; } - /* it looks complicated but gcc can optimize it away when constants - * have same values... In fact it depends on gcc :-( - */ - if (POLLIN == FD_POLL_IN && POLLOUT == FD_POLL_OUT && - POLLERR == FD_POLL_ERR && POLLHUP == FD_POLL_HUP) { - n = e & (POLLIN|POLLOUT|POLLERR|POLLHUP); - } - else { - n = ((e & POLLIN ) ? FD_POLL_IN : 0) | - ((e & POLLOUT) ? FD_POLL_OUT : 0) | - ((e & POLLERR) ? FD_POLL_ERR : 0) | - ((e & POLLHUP) ? FD_POLL_HUP : 0); - } + n = ((e & POLLIN) ? FD_EV_READY_R : 0) | + ((e & POLLOUT) ? FD_EV_READY_W : 0) | + ((e & POLLRDHUP) ? FD_EV_SHUT_R : 0) | + ((e & POLLHUP) ? FD_EV_SHUT_RW : 0) | + ((e & POLLERR) ? FD_EV_ERR_RW : 0); - /* always remap RDHUP to HUP as they're used similarly */ - if (e & POLLRDHUP) { + if ((e & POLLRDHUP) && !(cur_poller.flags & HAP_POLL_F_RDHUP)) _HA_ATOMIC_OR(&cur_poller.flags, HAP_POLL_F_RDHUP); - n |= FD_POLL_HUP; - } + fd_update_events(fd, n); } diff --git a/src/ev_select.c b/src/ev_select.c index 7ee915ea5..dc66e7127 100644 --- a/src/ev_select.c +++ b/src/ev_select.c @@ -210,10 +210,10 @@ REGPRM3 static void _do_poll(struct poller *p, int exp, int wake) } if (FD_ISSET(fd, tmp_evts[DIR_RD])) - n |= FD_POLL_IN; + n |= FD_EV_READY_R; if (FD_ISSET(fd, tmp_evts[DIR_WR])) - n |= FD_POLL_OUT; + n |= FD_EV_READY_W; fd_update_events(fd, n); }