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 69c9a64..1ab345a 100644
--- a/src/ev_poll.c
+++ b/src/ev_poll.c
@@ -77,23 +77,35 @@
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;
}
}