Hi Willy,

Sending a patch proposal after like 40 hours of looking through what happens and what event we might be missing, im now changing +-40 lines of code.. And actually not 'really' changing the events requested.. But rather kinda bringing the old 'previous state' comparison back..

Lemme know if its okay like this, you would like the new variable to be renamed, the if/then/else restructured or just don't like it at all ;).
In the last case please do give a hint about what you would like instead :).

Regards,
PiBa-NL (Pieter)
From 21c191c036f740eb75a4fa59c23232b910cd695c Mon Sep 17 00:00:00 2001
From: PiBa-NL <piba.nl....@gmail.com>
Date: Sun, 15 Apr 2018 22:20:22 +0200
Subject: [PATCH] BUG/MEDIUM: kqueue/poll: only use EV_SET when actually
 needing to add or remove event filters

Avoid event filters being added twice or deleted while not present causing 
hanging requests.
Known reproduction:
With haproxy on a FreeBSD machine, and a IIS website with NTLM authentication 
and using http-tunnel haproxy would fail to receive the request with the added 
credentials to pass to the backend.
---
 include/types/fd.h |  1 +
 src/ev_kqueue.c    | 36 +++++++++++++++++++++++++-----------
 src/fd.c           |  1 +
 3 files changed, 27 insertions(+), 11 deletions(-)

diff --git a/include/types/fd.h b/include/types/fd.h
index 0902e7f..243d7bb 100644
--- a/include/types/fd.h
+++ b/include/types/fd.h
@@ -115,6 +115,7 @@ struct fdtab {
        __decl_hathreads(HA_SPINLOCK_T lock);
        unsigned long thread_mask;           /* mask of thread IDs authorized 
to process the task */
        unsigned long polled_mask;           /* mask of thread IDs currently 
polling this fd */
+       unsigned long polled_mask_write;     /* mask of thread IDs currently 
polling this fd */
        unsigned long update_mask;           /* mask of thread IDs having an 
update for fd */
        struct fdlist_entry cache;           /* Entry in the fdcache */
        void (*iocb)(int fd);                /* I/O handler */
diff --git a/src/ev_kqueue.c b/src/ev_kqueue.c
index a103ece..ecadec3 100644
--- a/src/ev_kqueue.c
+++ b/src/ev_kqueue.c
@@ -56,29 +56,43 @@ REGPRM2 static void _do_poll(struct poller *p, int exp)
                en = fdtab[fd].state;
 
                if (!(fdtab[fd].thread_mask & tid_bit) || !(en & 
FD_EV_POLLED_RW)) {
-                       if (!(fdtab[fd].polled_mask & tid_bit)) {
+                       if (!(fdtab[fd].polled_mask & tid_bit) && 
!(fdtab[fd].polled_mask_write & tid_bit)) {
                                /* fd was not watched, it's still not */
                                continue;
                        }
                        /* fd totally removed from poll list */
-                       EV_SET(&kev[changes++], fd, EVFILT_READ, EV_DELETE, 0, 
0, NULL);
-                       EV_SET(&kev[changes++], fd, EVFILT_WRITE, EV_DELETE, 0, 
0, NULL);
-                       HA_ATOMIC_AND(&fdtab[fd].polled_mask, ~tid_bit);
+                       if (fdtab[fd].polled_mask & tid_bit) {
+                               EV_SET(&kev[changes++], fd, EVFILT_READ, 
EV_DELETE, 0, 0, NULL);
+                               HA_ATOMIC_AND(&fdtab[fd].polled_mask, ~tid_bit);
+                       }
+                       if (fdtab[fd].polled_mask_write & tid_bit) {
+                               EV_SET(&kev[changes++], fd, EVFILT_WRITE, 
EV_DELETE, 0, 0, NULL);
+                               HA_ATOMIC_AND(&fdtab[fd].polled_mask_write, 
~tid_bit);
+                       }
                }
                else {
                        /* OK fd has to be monitored, it was either added or 
changed */
 
-                       if (en & FD_EV_POLLED_R)
-                               EV_SET(&kev[changes++], fd, EVFILT_READ, 
EV_ADD, 0, 0, NULL);
-                       else if (fdtab[fd].polled_mask & tid_bit)
+                       if (en & FD_EV_POLLED_R) {
+                               if (!(fdtab[fd].polled_mask & tid_bit)) {
+                                       EV_SET(&kev[changes++], fd, 
EVFILT_READ, EV_ADD, 0, 0, NULL);
+                                       HA_ATOMIC_OR(&fdtab[fd].polled_mask, 
tid_bit);
+                               }
+                       } else if (fdtab[fd].polled_mask & tid_bit) {
                                EV_SET(&kev[changes++], fd, EVFILT_READ, 
EV_DELETE, 0, 0, NULL);
+                               HA_ATOMIC_AND(&fdtab[fd].polled_mask, ~tid_bit);
+                       }
 
-                       if (en & FD_EV_POLLED_W)
-                               EV_SET(&kev[changes++], fd, EVFILT_WRITE, 
EV_ADD, 0, 0, NULL);
-                       else if (fdtab[fd].polled_mask & tid_bit)
+                       if (en & FD_EV_POLLED_W) {
+                               if (!(fdtab[fd].polled_mask_write & tid_bit)) {
+                                       EV_SET(&kev[changes++], fd, 
EVFILT_WRITE, EV_ADD, 0, 0, NULL);
+                                       
HA_ATOMIC_OR(&fdtab[fd].polled_mask_write, tid_bit);
+                               }
+                       } else if (fdtab[fd].polled_mask_write & tid_bit) {
                                EV_SET(&kev[changes++], fd, EVFILT_WRITE, 
EV_DELETE, 0, 0, NULL);
+                               HA_ATOMIC_AND(&fdtab[fd].polled_mask_write, 
~tid_bit);
+                       }
 
-                       HA_ATOMIC_OR(&fdtab[fd].polled_mask, tid_bit);
                }
        }
        if (changes)
diff --git a/src/fd.c b/src/fd.c
index 1af64e5..57aeb5c 100644
--- a/src/fd.c
+++ b/src/fd.c
@@ -369,6 +369,7 @@ static void fd_dodelete(int fd, int do_close)
        fdtab[fd].thread_mask = 0;
        if (do_close) {
                fdtab[fd].polled_mask = 0;
+               fdtab[fd].polled_mask_write = 0;
                close(fd);
        }
        HA_SPIN_UNLOCK(FD_LOCK, &fdtab[fd].lock);
-- 
2.10.1.windows.1

Reply via email to