Hi,

On Mon, Apr 16, 2018 at 03:37:34PM +0200, Olivier Houchard wrote:
> Hi Pieter,
> 
> On Fri, Apr 13, 2018 at 06:50:50AM +0000, Pi Ba wrote:
> > Using poll (startup with -dk) the request works properly.
> 
> After some discussion with Willy, we came with a solution that may fix your
> problem with kqueue.
> Can you test the attached patch and let me know if it fixes it for you ?
> 
> Thanks !
> 
> Olivier


Minor variation of the patch, that uses EV_RECEIPT if available, to avoid
scanning needlessly the kqueue.

Regards,

Olivier
>From 2229159329ec539c7875943af08c539064dcd76b Mon Sep 17 00:00:00 2001
From: Olivier Houchard <ohouch...@haproxy.com>
Date: Mon, 16 Apr 2018 13:24:48 +0200
Subject: [PATCH] BUG/MEDIUM: When adding new events, provide an output to get
 errors.

When adding new events using kevent(), if there's an error, because we're
trying to delete an event that wasn't there, or because the fd has already
been closed, kevent() will either add an event in the eventlist array if
there's enough room for it, and keep on handling other events, or stop and
return -1.
We want it to process all the events, so give it a large-enough array to
store any error.

This should be backported to 1.8.
---
 src/ev_kqueue.c | 25 +++++++++++++++++++++----
 1 file changed, 21 insertions(+), 4 deletions(-)

diff --git a/src/ev_kqueue.c b/src/ev_kqueue.c
index a103ece9d..4306c4372 100644
--- a/src/ev_kqueue.c
+++ b/src/ev_kqueue.c
@@ -31,6 +31,7 @@
 /* private data */
 static int kqueue_fd[MAX_THREADS]; // per-thread kqueue_fd
 static THREAD_LOCAL struct kevent *kev = NULL;
+static struct kevent *kev_out = NULL; // Trash buffer for kevent() to write 
the eventlist in
 
 /*
  * kqueue() poller
@@ -43,6 +44,8 @@ REGPRM2 static void _do_poll(struct poller *p, int exp)
        int updt_idx, en;
        int changes = 0;
 
+       timeout.tv_sec  = 0;
+       timeout.tv_nsec = 0;
        /* first, scan the update list to find changes */
        for (updt_idx = 0; updt_idx < fd_nbupdt; updt_idx++) {
                fd = fd_updt[updt_idx];
@@ -81,13 +84,15 @@ REGPRM2 static void _do_poll(struct poller *p, int exp)
                        HA_ATOMIC_OR(&fdtab[fd].polled_mask, tid_bit);
                }
        }
-       if (changes)
-               kevent(kqueue_fd[tid], kev, changes, NULL, 0, NULL);
+       if (changes) {
+#ifdef EV_RECEIPT
+               kev[0].flags |= EV_RECEIPT;
+#endif
+               kevent(kqueue_fd[tid], kev, changes, kev_out, changes, 
&timeout);
+       }
        fd_nbupdt = 0;
 
        delta_ms        = 0;
-       timeout.tv_sec  = 0;
-       timeout.tv_nsec = 0;
 
        if (!exp) {
                delta_ms        = MAX_DELAY_MS;
@@ -194,6 +199,10 @@ REGPRM1 static int _do_init(struct poller *p)
 {
        p->private = NULL;
 
+       kev_out = calloc(1, sizeof(struct kevent) * 2 * global.maxsock);
+       if (!kev_out)
+               goto fail_alloc;
+
        kqueue_fd[tid] = kqueue();
        if (kqueue_fd[tid] < 0)
                goto fail_fd;
@@ -203,6 +212,9 @@ REGPRM1 static int _do_init(struct poller *p)
        return 1;
 
  fail_fd:
+       free(kev_out);
+       kev_out = NULL;
+fail_alloc:
        p->pref = 0;
        return 0;
 }
@@ -220,6 +232,10 @@ REGPRM1 static void _do_term(struct poller *p)
 
        p->private = NULL;
        p->pref = 0;
+       if (kev_out) {
+               free(kev_out);
+               kev_out = NULL;
+       }
 }
 
 /*
@@ -250,6 +266,7 @@ REGPRM1 static int _do_fork(struct poller *p)
        return 1;
 }
 
+
 /*
  * It is a constructor, which means that it will automatically be called before
  * main(). This is GCC-specific but it works at least since 2.95.
-- 
2.14.3

Reply via email to