mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-09-22 14:21:25 +02:00
BUG/MAJOR: threads/time: Store the time deviation in an 64-bits integer
In function tv_update_date, we keep an offset reprenting the time deviation to adjust the system time. At every call, we check if this offset must be updated or not. Of course, It must be shared by all threads. It was store in a timeval. But it cannot be atomically updated. So now, instead, we store it in a 64-bits integer. And in tv_update_date, we convert this integer in a timeval. Once updated, it is converted back in an integer to be atomically stored. To store a tv_offset into an integer, we use 32 bits from tv_sec and 32 bits tv_usec to avoid shift operations.
This commit is contained in:
parent
6e0128630b
commit
99aad9295b
35
src/time.c
35
src/time.c
@ -15,6 +15,7 @@
|
|||||||
#include <common/config.h>
|
#include <common/config.h>
|
||||||
#include <common/standard.h>
|
#include <common/standard.h>
|
||||||
#include <common/time.h>
|
#include <common/time.h>
|
||||||
|
#include <common/hathreads.h>
|
||||||
|
|
||||||
THREAD_LOCAL unsigned int ms_left_scaled; /* milliseconds left for current second (0..2^32-1) */
|
THREAD_LOCAL unsigned int ms_left_scaled; /* milliseconds left for current second (0..2^32-1) */
|
||||||
THREAD_LOCAL unsigned int now_ms; /* internal date in milliseconds (may wrap) */
|
THREAD_LOCAL unsigned int now_ms; /* internal date in milliseconds (may wrap) */
|
||||||
@ -159,22 +160,51 @@ REGPRM2 int _tv_isgt(const struct timeval *tv1, const struct timeval *tv2)
|
|||||||
* value means that we have not expired the timeout). Calling it with (-1,*)
|
* value means that we have not expired the timeout). Calling it with (-1,*)
|
||||||
* sets both <date> and <now> to current date, and calling it with (0,1) simply
|
* sets both <date> and <now> to current date, and calling it with (0,1) simply
|
||||||
* updates the values.
|
* updates the values.
|
||||||
|
*
|
||||||
|
* tv_offset is used to adjust the current time (date), to have a monotonic time
|
||||||
|
* (now). It must be global and thread-safe. But a timeval cannot be atomically
|
||||||
|
* updated. So instead, we store it in a 64-bits integer (offset). And in
|
||||||
|
* tv_update_date, we convert this integer into a timeval (tv_offset). Once
|
||||||
|
* updated, it is converted back into an integer to be atomically stored.
|
||||||
|
*
|
||||||
|
* To store a tv_offset into an integer, we use 32 bits from tv_sec and 32 bits
|
||||||
|
* tv_usec to avoid shift operations.
|
||||||
*/
|
*/
|
||||||
|
#define OFFSET_TO_TIMEVAL(off, tv) \
|
||||||
|
do { \
|
||||||
|
unsigned long long __i = (off); \
|
||||||
|
(tv)->tv_sec = (__i << 32); \
|
||||||
|
(tv)->tv_usec = (__i & 0xFFFFFFFFU); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define TIMEVAL_TO_OFFSET(tv, off) \
|
||||||
|
do { \
|
||||||
|
unsigned long long __i = (((tv).tv_sec & 0xFFFFFFFFULL) << 32) + (unsigned int)(tv).tv_usec; \
|
||||||
|
HA_ATOMIC_STORE((off), __i); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define RESET_OFFSET(off) \
|
||||||
|
do { \
|
||||||
|
HA_ATOMIC_STORE((off), 0); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
REGPRM2 void tv_update_date(int max_wait, int interrupted)
|
REGPRM2 void tv_update_date(int max_wait, int interrupted)
|
||||||
{
|
{
|
||||||
static struct timeval tv_offset; /* warning: signed offset! */
|
static long long offset = 0; /* warning: signed offset! */
|
||||||
|
struct timeval tv_offset; /* offset converted into a timeval */
|
||||||
struct timeval adjusted, deadline;
|
struct timeval adjusted, deadline;
|
||||||
unsigned int curr_sec_ms; /* millisecond of current second (0..999) */
|
unsigned int curr_sec_ms; /* millisecond of current second (0..999) */
|
||||||
|
|
||||||
gettimeofday(&date, NULL);
|
gettimeofday(&date, NULL);
|
||||||
if (unlikely(max_wait < 0)) {
|
if (unlikely(max_wait < 0)) {
|
||||||
tv_zero(&tv_offset);
|
RESET_OFFSET(&offset);
|
||||||
adjusted = date;
|
adjusted = date;
|
||||||
after_poll = date;
|
after_poll = date;
|
||||||
samp_time = idle_time = 0;
|
samp_time = idle_time = 0;
|
||||||
idle_pct = 100;
|
idle_pct = 100;
|
||||||
goto to_ms;
|
goto to_ms;
|
||||||
}
|
}
|
||||||
|
OFFSET_TO_TIMEVAL(offset, &tv_offset);
|
||||||
__tv_add(&adjusted, &date, &tv_offset);
|
__tv_add(&adjusted, &date, &tv_offset);
|
||||||
if (unlikely(__tv_islt(&adjusted, &now))) {
|
if (unlikely(__tv_islt(&adjusted, &now))) {
|
||||||
goto fixup; /* jump in the past */
|
goto fixup; /* jump in the past */
|
||||||
@ -200,6 +230,7 @@ REGPRM2 void tv_update_date(int max_wait, int interrupted)
|
|||||||
tv_offset.tv_usec += 1000000;
|
tv_offset.tv_usec += 1000000;
|
||||||
tv_offset.tv_sec--;
|
tv_offset.tv_sec--;
|
||||||
}
|
}
|
||||||
|
TIMEVAL_TO_OFFSET(tv_offset, &offset);
|
||||||
to_ms:
|
to_ms:
|
||||||
now = adjusted;
|
now = adjusted;
|
||||||
curr_sec_ms = now.tv_usec / 1000; /* ms of current second */
|
curr_sec_ms = now.tv_usec / 1000; /* ms of current second */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user