From: Willy Tarreau Date: Wed, 24 Jun 2026 15:47:49 +0000 (+0200) Subject: BUG/MINOR: poller: fix wait time calculation that is always 1 extra ms X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=55744154b4e01079c2cd39d6730b7e68ea8c92fc;p=thirdparty%2Fhaproxy.git BUG/MINOR: poller: fix wait time calculation that is always 1 extra ms In 1.3.11, 19 years ago, commit bdefc513a0 ("[BUG] fix null timeouts in *poll-based pollers") addressed an issue where some wakeup times could sometimes be rounded to less than one millisecond (by then they were calculated on timeval), and would make the poller wake up too early and loop with a timeout of zero. The solution used by then consisted in always adding 1 to the wait delay so that poll() was never called with a null timeout. Nowadays our internal wakeup delays are in milliseconds so we cannot wake too early, all the timeout calculation was moved to compute_poll_timeout() which has a specific check for expired next wakeup event, so we cannot even have a null timeout as a result of a real delay calculation by accident. Yet, it's clearly visible with strace thats a task created with an interval of 10ms results in a poll timeout of 11ms, causing some small time drift in periodic wakeups. Let's just now drop this "+1" which is no longer needed nor relevant and only causes wrong delays to be calculated. Now creating a time-printing task results in correct delays passed to poll() and measured intervals around: - ~10.3ms interval for 10ms - ~100.5ms for 100ms - ~1001ms for 1000ms E.g: $ socat - /tmp/sock1 <<< "expert-mode on;debug dev sched task print=1 inter=10 count=1" (...) 17:58:05.191885 clock_gettime(CLOCK_THREAD_CPUTIME_ID, {tv_sec=0, tv_nsec=44590744}) = 0 17:58:05.191919 epoll_wait(4, [], 200, 10) = 0 17:58:05.202215 clock_gettime(CLOCK_THREAD_CPUTIME_ID, {tv_sec=0, tv_nsec=44601494}) = 0 17:58:05.202237 write(1, "task 0x3aeeb080: time_ms=3553"..., 42task 0x3aeeb080: time_ms=355304053.757383 ) = 42 17:58:05.202253 clock_gettime(CLOCK_THREAD_CPUTIME_ID, {tv_sec=0, tv_nsec=44610199}) = 0 17:58:05.202265 epoll_wait(4, [], 200, 10) = 0 17:58:05.212579 clock_gettime(CLOCK_THREAD_CPUTIME_ID, {tv_sec=0, tv_nsec=44631754}) = 0 17:58:05.212639 write(1, "task 0x3aeeb080: time_ms=3553"..., 42task 0x3aeeb080: time_ms=355304064.157626 ) = 42 These delays with longer sleeps are entirely on the system side, most likely due to the CPU switching to low-power for such long delays (tests run on a laptop). There is no reason to backport this fix, though it shouldn't hurt either. --- diff --git a/src/fd.c b/src/fd.c index 7b468d264..6e7276f38 100644 --- a/src/fd.c +++ b/src/fd.c @@ -1069,7 +1069,7 @@ int compute_poll_timeout(int next) wait_time = 0; } else { - wait_time = TICKS_TO_MS(tick_remain(now_ms, next)) + 1; + wait_time = TICKS_TO_MS(tick_remain(now_ms, next)); if (wait_time > MAX_DELAY_MS) wait_time = MAX_DELAY_MS; }