From: Willy Tarreau Date: Thu, 25 Jan 2018 16:11:33 +0000 (+0100) Subject: MEDIUM: poll: don't use the old FD state anymore X-Git-Tag: v1.9-dev1~471 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=fc6eea4de24fbefa24115fb0b51f629b742da1e2;p=thirdparty%2Fhaproxy.git MEDIUM: poll: don't use the old FD state anymore The polling updates are now performed exactly like the epoll/kqueue ones : only the new polled state is considered, and the previous one is checked using polled_mask. The only specific stuff here is that the fd state is shared between all threads, so an FD removal has to be done only once. --- diff --git a/src/ev_poll.c b/src/ev_poll.c index 69c9a648cf..1ab345a6a4 100644 --- a/src/ev_poll.c +++ b/src/ev_poll.c @@ -77,23 +77,35 @@ REGPRM2 static void _do_poll(struct poller *p, int exp) fdtab[fd].state = en; HA_SPIN_UNLOCK(FD_LOCK, &fdtab[fd].lock); - if ((eo ^ en) & FD_EV_POLLED_RW) { - /* poll status changed, update the lists */ - if ((eo & ~en) & FD_EV_POLLED_R) + /* we have a single state for all threads, which is why we + * don't check the tid_bit. First thread to see the update + * takes it for every other one. + */ + if (!(en & FD_EV_POLLED_RW)) { + if (!fdtab[fd].polled_mask) { + /* fd was not watched, it's still not */ + continue; + } + /* fd totally removed from poll list */ + hap_fd_clr(fd, fd_evts[DIR_RD]); + hap_fd_clr(fd, fd_evts[DIR_WR]); + HA_ATOMIC_AND(&fdtab[fd].polled_mask, 0); + } + else { + /* OK fd has to be monitored, it was either added or changed */ + if (!(en & FD_EV_POLLED_R)) hap_fd_clr(fd, fd_evts[DIR_RD]); - else if ((en & ~eo) & FD_EV_POLLED_R) { + else hap_fd_set(fd, fd_evts[DIR_RD]); - if (fd > max_add_fd) - max_add_fd = fd; - } - if ((eo & ~en) & FD_EV_POLLED_W) + if (!(en & FD_EV_POLLED_W)) hap_fd_clr(fd, fd_evts[DIR_WR]); - else if ((en & ~eo) & FD_EV_POLLED_W) { + else hap_fd_set(fd, fd_evts[DIR_WR]); - if (fd > max_add_fd) - max_add_fd = fd; - } + + HA_ATOMIC_OR(&fdtab[fd].polled_mask, tid_bit); + if (fd > max_add_fd) + max_add_fd = fd; } }