]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MINOR: polling: fix time reporting when using busy polling
authorWilly Tarreau <w@1wt.eu>
Thu, 12 Sep 2024 15:47:13 +0000 (17:47 +0200)
committerWilly Tarreau <w@1wt.eu>
Thu, 12 Sep 2024 15:47:13 +0000 (17:47 +0200)
Since commit beb859abce ("MINOR: polling: add an option to support
busy polling") the time and status passed to clock_update_local_date()
were incorrect. Indeed, what is considered is the before_poll date
related to the configured timeout which does not correspond to what
is passed to the poller. That's not correct because before_poll+the
syscall's timeout will be crossed by the current date 100 ms after
the start of the poller. In practice it didn't happen when the poller
was limited to 1s timeout but at one minute it happens all the time.

That's particularly visible when running a multi-threaded setup with
busy polling and only half of the threads working (bind ... thread even).
In this case, the fixup code of clock_update_local_date() is executed
for each round of busy polling. The issue was made really visible
starting with recent commit e8b1ad4c2b ("BUG/MEDIUM: clock: also
update the date offset on time jumps") because upon a jump, the
shared offset is reset, while it should not be in this specific
case.

What needs to be done instead is to pass the configured timeout of
the poller (and not of the syscall), and always pass "interrupted"
set so as to claim we got an event (which is sort of true as it just
means the poller returned instantly). In this case we can still
detect backwards/forward jumps and will use a correct boundary
for the maximum date that covers the whole loop.

This can be backported to all versions since the issue was introduced
with busy-polling in 1.9-dev8.

src/ev_epoll.c
src/ev_evports.c
src/ev_kqueue.c

index 352620d0a3db1056461be5f4d6c4e375554dd6c5..9e7050c730821c0b7be1f511b2522c7b62e18e8a 100644 (file)
@@ -230,7 +230,7 @@ static void _do_poll(struct poller *p, int exp, int wake)
                int timeout = (global.tune.options & GTUNE_BUSY_POLLING) ? 0 : wait_time;
 
                status = epoll_wait(epoll_fd[tid], epoll_events, global.tune.maxpollevents, timeout);
-               clock_update_local_date(timeout, status);
+               clock_update_local_date(wait_time, (global.tune.options & GTUNE_BUSY_POLLING) ? 1 : status);
 
                if (status) {
                        activity[tid].poll_io++;
index ee357bc1f4d2cc64b9230308d27510d334a402d7..da2c11060d397a7c30cadd432f97795b5b5d0dd6 100644 (file)
@@ -225,7 +225,7 @@ static void _do_poll(struct poller *p, int exp, int wake)
                                break;
                        }
                }
-               clock_update_local_date(timeout, nevlist);
+               clock_update_local_date(wait_time, (global.tune.options & GTUNE_BUSY_POLLING) ? 1 : nevlist);
 
                if (nevlist || interrupted)
                        break;
index f123e7be25320cb3ed04a4e571d59a443d42dc3c..271e95b672c0e2778ca4ef55ef84c2f388b2ed91 100644 (file)
@@ -183,7 +183,7 @@ static void _do_poll(struct poller *p, int exp, int wake)
                                kev,       // struct kevent *eventlist
                                fd,        // int nevents
                                &timeout_ts); // const struct timespec *timeout
-               clock_update_local_date(timeout, status);
+               clock_update_local_date(wait_time, (global.tune.options & GTUNE_BUSY_POLLING) ? 1 : status);
 
                if (status) {
                        activity[tid].poll_io++;