MEDIUM: fd: do not use the FD_POLL_* flags in the pollers anymore

As mentioned in previous commit, these flags do not map well to
modern poller capabilities. Let's use the FD_EV_*_{R,W} flags instead.
This first patch only performs a 1-to-1 mapping making sure that the
previously reported flags are still reported identically while using
the closest possible semantics in the pollers.

It's worth noting that kqueue will now support improvements such as
returning distinctions between shut and errors on each direction,
though this is not exploited for now.
This commit is contained in:
Willy Tarreau 2019-09-06 19:05:50 +02:00
parent 77abb43ed1
commit 6b3089856f
6 changed files with 43 additions and 57 deletions

View File

@ -318,20 +318,32 @@ static inline void fd_want_send(int fd)
updt_fd_polling(fd);
}
/* Update events seen for FD <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 <fd> and its state if needed. This should be
* called by the poller, passing FD_EV_*_{R,W,RW} in <evts>. 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;

View File

@ -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 */

View File

@ -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

View File

@ -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);

View File

@ -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);
}

View File

@ -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);
}