From: Willy Tarreau Date: Fri, 8 Oct 2021 07:33:24 +0000 (+0200) Subject: REORG: time: move time-keeping code and variables to clock.c X-Git-Tag: v2.5-dev9~28 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=5554264f314578a3576ba08825c1158b6c4c96a2;p=thirdparty%2Fhaproxy.git REORG: time: move time-keeping code and variables to clock.c There is currently a problem related to time keeping. We're mixing the functions to perform calculations with the os-dependent code needed to retrieve and adjust the local time. This patch extracts from time.{c,h} the parts that are solely dedicated to time keeping. These are the "now" or "before_poll" variables for example, as well as the various now_*() functions that make use of gettimeofday() and clock_gettime() to retrieve the current time. The "tv_*" functions moved there were also more appropriately renamed to "clock_*". Other parts used to compute stolen time are in other files, they will have to be picked next. --- diff --git a/Makefile b/Makefile index 998a17dc3b..9401237815 100644 --- a/Makefile +++ b/Makefile @@ -886,7 +886,7 @@ OBJS += src/mux_h2.o src/mux_fcgi.o src/http_ana.o src/mux_h1.o src/stream.o \ src/time.o src/signal.o src/mworker-prog.o src/hpack-dec.o src/fix.o \ src/arg.o src/eb64tree.o src/chunk.o src/shctx.o src/regex.o \ src/fcgi.o src/eb32tree.o src/eb32sctree.o src/dynbuf.o src/uri_auth.o \ - src/hpack-tbl.o src/ebimtree.o src/auth.o src/ebsttree.o \ + src/hpack-tbl.o src/ebimtree.o src/auth.o src/ebsttree.o src/clock.o \ src/ebistree.o src/base64.o src/wdt.o src/pipe.o src/http_acl.o \ src/hpack-enc.o src/dict.o src/dgram.o src/init.o src/hpack-huff.o \ src/freq_ctr.o src/ebtree.o src/hash.o src/version.o src/errors.o \ diff --git a/addons/ot/include/include.h b/addons/ot/include/include.h index f185a53b21..f1a567240a 100644 --- a/addons/ot/include/include.h +++ b/addons/ot/include/include.h @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include diff --git a/include/haproxy/backend.h b/include/haproxy/backend.h index 8a763bfbdc..17dffac8a9 100644 --- a/include/haproxy/backend.h +++ b/include/haproxy/backend.h @@ -24,10 +24,10 @@ #include #include +#include #include #include #include -#include int assign_server(struct stream *s); int assign_server_address(struct stream *s); diff --git a/include/haproxy/clock.h b/include/haproxy/clock.h new file mode 100644 index 0000000000..045ab5a405 --- /dev/null +++ b/include/haproxy/clock.h @@ -0,0 +1,45 @@ +/* + * include/haproxy/clock.h + * Exported parts for time-keeping + * + * Copyright (C) 2000-2021 Willy Tarreau - w@1wt.eu + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation, version 2.1 + * exclusively. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _HAPROXY_CLOCK_H +#define _HAPROXY_CLOCK_H + +#include +#include +#include + +extern struct timeval start_date; /* the process's start date in wall-clock time */ +extern volatile ullong global_now; /* common monotonic date between all threads (32:32) */ + +extern THREAD_LOCAL struct timeval now; /* internal monotonic date derived from real clock */ +extern THREAD_LOCAL struct timeval date; /* the real current date (wall-clock time) */ +extern THREAD_LOCAL struct timeval before_poll; /* system date before calling poll() */ +extern THREAD_LOCAL struct timeval after_poll; /* system date after leaving poll() */ + +uint64_t now_cpu_time_thread(const struct thread_info *thr); +uint64_t now_mono_time(void); +uint64_t now_cpu_time(void); +void clock_update_date(int max_wait, int interrupted); +void clock_init_process_date(void); +void clock_init_thread_date(void); +char *timeofday_as_iso_us(int pad); + +#endif diff --git a/include/haproxy/task.h b/include/haproxy/task.h index e2c8a9909e..4acbcad964 100644 --- a/include/haproxy/task.h +++ b/include/haproxy/task.h @@ -30,6 +30,7 @@ #include #include +#include #include #include #include @@ -38,7 +39,6 @@ #include #include #include -#include /* Principle of the wait queue. diff --git a/include/haproxy/time.h b/include/haproxy/time.h index d1f181c7b9..97b4ee256b 100644 --- a/include/haproxy/time.h +++ b/include/haproxy/time.h @@ -1,6 +1,6 @@ /* * include/haproxy/time.h - * Time calculation functions and macros. + * timeval-based time calculation functions and macros. * * Copyright (C) 2000-2020 Willy Tarreau - w@1wt.eu * @@ -23,22 +23,10 @@ #define _HAPROXY_TIME_H #include -#include #include -#include #define TIME_ETERNITY (TV_ETERNITY_MS) -/* returns the lowest delay amongst and , and respects TIME_ETERNITY */ -#define MINTIME(old, new) (((new)<0)?(old):(((old)<0||(new)<(old))?(new):(old))) -#define SETNOW(a) (*a=now) - -extern THREAD_LOCAL struct timeval now; /* internal date is a monotonic function of real clock */ -extern THREAD_LOCAL struct timeval date; /* the real current date */ -extern struct timeval start_date; /* the process's start date */ -extern THREAD_LOCAL struct timeval before_poll; /* system date before calling poll() */ -extern THREAD_LOCAL struct timeval after_poll; /* system date after leaving poll() */ -extern volatile unsigned long long global_now; /**** exported functions *************************************************/ @@ -59,30 +47,10 @@ int tv_ms_cmp(const struct timeval *tv1, const struct timeval *tv2); */ int tv_ms_cmp2(const struct timeval *tv1, const struct timeval *tv2); -/* tv_udpate_date: sets to system time, and sets to something as - * close as possible to real time, following a monotonic function. The main - * principle consists in detecting backwards and forwards time jumps and adjust - * an offset to correct them. This function should be called only once after - * each poll. The poll's timeout should be passed in , and the return - * value in (a non-zero value means that we have not expired the - * timeout). - */ -void tv_update_date(int max_wait, int interrupted); -void tv_init_process_date(void); -void tv_init_thread_date(void); - -char *timeofday_as_iso_us(int pad); /**** general purpose functions and macros *******************************/ -/* tv_now: sets to the current time */ -static inline struct timeval *tv_now(struct timeval *tv) -{ - gettimeofday(tv, NULL); - return tv; -} - /* * sets a struct timeval to its highest value so that it can never happen * note that only tv_usec is necessary to detect it since a tv_usec > 999999 @@ -496,42 +464,6 @@ static inline struct timeval *__tv_ms_add(struct timeval *tv, const struct timev tv1; \ }) -/* returns the system's monotonic time in nanoseconds if supported, otherwise zero */ -static inline uint64_t now_mono_time() -{ -#if (_POSIX_TIMERS > 0) && defined(_POSIX_MONOTONIC_CLOCK) - struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - return ts.tv_sec * 1000000000ULL + ts.tv_nsec; -#else - return 0; -#endif -} - -/* returns the current thread's cumulated CPU time in nanoseconds if supported, otherwise zero */ -static inline uint64_t now_cpu_time() -{ -#if (_POSIX_TIMERS > 0) && defined(_POSIX_THREAD_CPUTIME) - struct timespec ts; - clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts); - return ts.tv_sec * 1000000000ULL + ts.tv_nsec; -#else - return 0; -#endif -} - -/* returns another thread's cumulated CPU time in nanoseconds if supported, otherwise zero */ -static inline uint64_t now_cpu_time_thread(const struct thread_info *thr) -{ -#if (_POSIX_TIMERS > 0) && defined(_POSIX_THREAD_CPUTIME) - struct timespec ts; - clock_gettime(thr->clock_id, &ts); - return ts.tv_sec * 1000000000ULL + ts.tv_nsec; -#else - return 0; -#endif -} - #endif /* _HAPROXY_TIME_H */ /* diff --git a/src/activity.c b/src/activity.c index c3010c5f3a..a2d31898c2 100644 --- a/src/activity.c +++ b/src/activity.c @@ -13,11 +13,11 @@ #include #include #include +#include #include #include #include #include -#include #include #include diff --git a/src/cfgparse.c b/src/cfgparse.c index 2ef62afbe1..7aeffaaf4f 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -46,6 +46,7 @@ #include #include #include +#include #ifdef USE_CPU_AFFINITY #include #endif @@ -82,7 +83,6 @@ #include #include #include -#include #include #include #include @@ -2403,7 +2403,7 @@ int check_config_validity() */ /* will be needed further to delay some tasks */ - tv_update_date(0,1); + clock_update_date(0,1); if (!global.tune.max_http_hdr) global.tune.max_http_hdr = MAX_HTTP_HDR; diff --git a/src/clock.c b/src/clock.c new file mode 100644 index 0000000000..ecaeca9285 --- /dev/null +++ b/src/clock.c @@ -0,0 +1,253 @@ +/* + * General time-keeping code and variables + * + * Copyright 2000-2021 Willy Tarreau + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include +#include + +#include +#include +#include +#include +#include + +struct timeval start_date; /* the process's start date in wall-clock time */ +volatile ullong global_now; /* common monotonic date between all threads (32:32) */ +volatile uint global_now_ms; /* common monotonic date in milliseconds (may wrap) */ + +THREAD_ALIGNED(64) static ullong now_offset; /* global offset between system time and global time */ + +THREAD_LOCAL uint now_ms; /* internal monotonic date in milliseconds (may wrap) */ +THREAD_LOCAL struct timeval now; /* internal monotonic date derived from real clock */ +THREAD_LOCAL struct timeval date; /* the real current date (wall-clock time) */ +THREAD_LOCAL struct timeval before_poll; /* system date before calling poll() */ +THREAD_LOCAL struct timeval after_poll; /* system date after leaving poll() */ + +static THREAD_LOCAL unsigned int iso_time_sec; /* last iso time value for this thread */ +static THREAD_LOCAL char iso_time_str[34]; /* ISO time representation of gettimeofday() */ + +/* returns the system's monotonic time in nanoseconds if supported, otherwise zero */ +uint64_t now_mono_time(void) +{ + uint64_t ret = 0; +#if defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0) && defined(_POSIX_MONOTONIC_CLOCK) + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + ret = ts.tv_sec * 1000000000ULL + ts.tv_nsec; +#endif + return ret; +} + +/* returns the current thread's cumulated CPU time in nanoseconds if supported, otherwise zero */ +uint64_t now_cpu_time(void) +{ + uint64_t ret = 0; +#if defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0) && defined(_POSIX_THREAD_CPUTIME) + struct timespec ts; + clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts); + ret = ts.tv_sec * 1000000000ULL + ts.tv_nsec; +#endif + return ret; +} + +/* returns another thread's cumulated CPU time in nanoseconds if supported, otherwise zero */ +uint64_t now_cpu_time_thread(const struct thread_info *thr) +{ + uint64_t ret = 0; +#if defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0) && defined(_POSIX_THREAD_CPUTIME) + struct timespec ts; + clock_gettime(thr->clock_id, &ts); + ret = ts.tv_sec * 1000000000ULL + ts.tv_nsec; +#endif + return ret; +} + +/* clock_update_date: sets to system time, and sets to something as + * close as possible to real time, following a monotonic function. The main + * principle consists in detecting backwards and forwards time jumps and adjust + * an offset to correct them. This function should be called once after each + * poll, and never farther apart than MAX_DELAY_MS*2. The poll's timeout should + * be passed in , and the return value in (a non-zero + * value means that we have not expired the timeout). + * + * clock_init_process_date() must have been called once first, and + * clock_init_thread_date() must also have been called once for each thread. + * + * An offset is used to adjust the current time (date), to figure a monotonic + * local time (now). The offset is not critical, as it is only updated after a + * clock jump is detected. From this point all threads will apply it to their + * locally measured time, and will then agree around a common monotonic + * global_now value that serves to further refine their local time. As it is + * not possible to atomically update a timeval, both global_now and the + * now_offset values are instead stored as 64-bit integers made of two 32 bit + * values for the tv_sec and tv_usec parts. The offset is made of two signed + * ints so that the clock can be adjusted in the two directions. + */ +void clock_update_date(int max_wait, int interrupted) +{ + struct timeval min_deadline, max_deadline, tmp_now; + uint old_now_ms; + ullong old_now; + ullong new_now; + ullong ofs, ofs_new; + uint sec_ofs, usec_ofs; + + gettimeofday(&date, NULL); + + /* compute the minimum and maximum local date we may have reached based + * on our past date and the associated timeout. There are three possible + * extremities: + * - the new date cannot be older than before_poll + * - if not interrupted, the new date cannot be older than + * before_poll+max_wait + * - in any case the new date cannot be newer than + * before_poll+max_wait+some margin (100ms used here). + * In case of violation, we'll ignore the current date and instead + * restart from the last date we knew. + */ + _tv_ms_add(&min_deadline, &before_poll, max_wait); + _tv_ms_add(&max_deadline, &before_poll, max_wait + 100); + + ofs = HA_ATOMIC_LOAD(&now_offset); + + if (unlikely(__tv_islt(&date, &before_poll) || // big jump backwards + (!interrupted && __tv_islt(&date, &min_deadline)) || // small jump backwards + __tv_islt(&max_deadline, &date))) { // big jump forwards + if (!interrupted) + _tv_ms_add(&now, &now, max_wait); + } else { + /* The date is still within expectations. Let's apply the + * now_offset to the system date. Note: ofs if made of two + * independent signed ints. + */ + now.tv_sec = date.tv_sec + (int)(ofs >> 32); // note: may be positive or negative + now.tv_usec = date.tv_usec + (int)ofs; // note: may be positive or negative + if ((int)now.tv_usec < 0) { + now.tv_usec += 1000000; + now.tv_sec -= 1; + } else if (now.tv_usec >= 1000000) { + now.tv_usec -= 1000000; + now.tv_sec += 1; + } + } + + /* now that we have bounded the local time, let's check if it's + * realistic regarding the global date, which only moves forward, + * otherwise catch up. + */ + old_now = global_now; + old_now_ms = global_now_ms; + + do { + tmp_now.tv_sec = (unsigned int)(old_now >> 32); + tmp_now.tv_usec = old_now & 0xFFFFFFFFU; + + if (__tv_islt(&now, &tmp_now)) + now = tmp_now; + + /* now is expected to be the most accurate date, + * equal to or newer. + */ + new_now = ((ullong)now.tv_sec << 32) + (uint)now.tv_usec; + now_ms = __tv_to_ms(&now); + + /* let's try to update the global (both in timeval + * and ms forms) or loop again. + */ + } while (((new_now != old_now && !_HA_ATOMIC_CAS(&global_now, &old_now, new_now)) || + (now_ms != old_now_ms && !_HA_ATOMIC_CAS(&global_now_ms, &old_now_ms, now_ms))) && + __ha_cpu_relax()); + + /* and are now updated to the last value of global_now + * and global_now_ms, which were also monotonically updated. We can + * compute the latest offset, we don't care who writes it last, the + * variations will not break the monotonic property. + */ + + sec_ofs = now.tv_sec - date.tv_sec; + usec_ofs = now.tv_usec - date.tv_usec; + if ((int)usec_ofs < 0) { + usec_ofs += 1000000; + sec_ofs -= 1; + } + ofs_new = ((ullong)sec_ofs << 32) + usec_ofs; + if (ofs_new != ofs) + HA_ATOMIC_STORE(&now_offset, ofs_new); +} + +/* must be called once at boot to initialize some global variables */ +void clock_init_process_date(void) +{ + now_offset = 0; + gettimeofday(&date, NULL); + now = after_poll = before_poll = date; + global_now = ((ullong)date.tv_sec << 32) + (uint)date.tv_usec; + global_now_ms = now.tv_sec * 1000 + now.tv_usec / 1000; + ti->idle_pct = 100; + clock_update_date(0, 1); +} + +/* must be called once per thread to initialize their thread-local variables. + * Note that other threads might also be initializing and running in parallel. + */ +void clock_init_thread_date(void) +{ + ullong old_now; + + gettimeofday(&date, NULL); + after_poll = before_poll = date; + + old_now = _HA_ATOMIC_LOAD(&global_now); + now.tv_sec = old_now >> 32; + now.tv_usec = (uint)old_now; + ti->idle_pct = 100; + clock_update_date(0, 1); +} + +/* returns the current date as returned by gettimeofday() in ISO+microsecond + * format. It uses a thread-local static variable that the reader can consume + * for as long as it wants until next call. Thus, do not call it from a signal + * handler. If is non-0, a trailing space will be added. It will always + * return exactly 32 or 33 characters (depending on padding) and will always be + * zero-terminated, thus it will always fit into a 34 bytes buffer. + * This also always include the local timezone (in +/-HH:mm format) . + */ +char *timeofday_as_iso_us(int pad) +{ + struct timeval new_date; + struct tm tm; + const char *offset; + char c; + + gettimeofday(&new_date, NULL); + if (new_date.tv_sec != iso_time_sec || !new_date.tv_sec) { + get_localtime(new_date.tv_sec, &tm); + offset = get_gmt_offset(new_date.tv_sec, &tm); + if (unlikely(strftime(iso_time_str, sizeof(iso_time_str), "%Y-%m-%dT%H:%M:%S.000000+00:00", &tm) != 32)) + strcpy(iso_time_str, "YYYY-mm-ddTHH:MM:SS.000000-00:00"); // make the failure visible but respect format. + iso_time_str[26] = offset[0]; + iso_time_str[27] = offset[1]; + iso_time_str[28] = offset[2]; + iso_time_str[30] = offset[3]; + iso_time_str[31] = offset[4]; + iso_time_sec = new_date.tv_sec; + } + + /* utoa_pad adds a trailing 0 so we save the char for restore */ + c = iso_time_str[26]; + utoa_pad(new_date.tv_usec, iso_time_str + 20, 7); + iso_time_str[26] = c; + if (pad) { + iso_time_str[32] = ' '; + iso_time_str[33] = 0; + } + return iso_time_str; +} diff --git a/src/debug.c b/src/debug.c index 303e28269f..c5b78edc7b 100644 --- a/src/debug.c +++ b/src/debug.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -33,6 +34,7 @@ #include #include #include +#include #include #include diff --git a/src/ev_epoll.c b/src/ev_epoll.c index d376cd994a..03888d0a39 100644 --- a/src/ev_epoll.c +++ b/src/ev_epoll.c @@ -16,12 +16,12 @@ #include #include +#include #include #include #include #include #include -#include #include @@ -195,7 +195,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); - tv_update_date(timeout, status); + clock_update_date(timeout, status); if (status) { activity[tid].poll_io++; diff --git a/src/ev_evports.c b/src/ev_evports.c index f8c7f34720..23bf11ffa0 100644 --- a/src/ev_evports.c +++ b/src/ev_evports.c @@ -20,12 +20,12 @@ #include #include +#include #include #include #include #include #include -#include /* * Private data: @@ -191,7 +191,7 @@ static void _do_poll(struct poller *p, int exp, int wake) break; } } - tv_update_date(timeout, nevlist); + clock_update_date(timeout, nevlist); if (nevlist || interrupted) break; diff --git a/src/ev_kqueue.c b/src/ev_kqueue.c index 3a53e07d67..df8eae263f 100644 --- a/src/ev_kqueue.c +++ b/src/ev_kqueue.c @@ -19,12 +19,12 @@ #include #include +#include #include #include #include #include #include -#include /* private data */ @@ -161,7 +161,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 - tv_update_date(timeout, status); + clock_update_date(timeout, status); if (status) { activity[tid].poll_io++; diff --git a/src/ev_poll.c b/src/ev_poll.c index b08bfcac2d..9b93c92e5d 100644 --- a/src/ev_poll.c +++ b/src/ev_poll.c @@ -19,11 +19,11 @@ #include #include +#include #include #include #include #include -#include #ifndef POLLRDHUP @@ -205,7 +205,7 @@ static void _do_poll(struct poller *p, int exp, int wake) sched_entering_poll(); activity_count_runtime(); status = poll(poll_events, nbfd, wait_time); - tv_update_date(wait_time, status); + clock_update_date(wait_time, status); sched_leaving_poll(wait_time, status); thread_harmless_end(); diff --git a/src/ev_select.c b/src/ev_select.c index 12c7341dd4..47da75dacf 100644 --- a/src/ev_select.c +++ b/src/ev_select.c @@ -16,11 +16,11 @@ #include #include +#include #include #include #include #include -#include /* private data */ @@ -180,7 +180,7 @@ static void _do_poll(struct poller *p, int exp, int wake) writenotnull ? tmp_evts[DIR_WR] : NULL, NULL, &delta); - tv_update_date(delta_ms, status); + clock_update_date(delta_ms, status); sched_leaving_poll(delta_ms, status); thread_harmless_end(); diff --git a/src/haproxy.c b/src/haproxy.c index 1ab2bf618a..618efb362f 100644 --- a/src/haproxy.c +++ b/src/haproxy.c @@ -95,6 +95,7 @@ #include #include #include +#include #include #ifdef USE_CPU_AFFINITY #include @@ -1506,7 +1507,7 @@ static void init(int argc, char **argv) #endif tzset(); - tv_init_process_date(); + clock_init_process_date(); start_date = now; ha_random_boot(argv); @@ -2615,7 +2616,7 @@ void run_poll_loop() { int next, wake; - tv_update_date(0,1); + clock_update_date(0,1); while (1) { wake_expired_tasks(); @@ -2720,7 +2721,7 @@ static void *run_thread_poll_loop(void *data) init_left = global.nbthread; init_left--; - tv_init_thread_date(); + clock_init_thread_date(); /* per-thread alloc calls performed here are not allowed to snoop on * other threads, so they are free to initialize at their own rhythm diff --git a/src/hlua.c b/src/hlua.c index 7e759548cf..d5d3f599fa 100644 --- a/src/hlua.c +++ b/src/hlua.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -1325,7 +1326,7 @@ void hlua_hook(lua_State *L, lua_Debug *ar) MAY_LJMP(hlua_yieldk(L, 0, 0, NULL, TICK_ETERNITY, HLUA_CTRLYIELD)); /* If we cannot yield, update the clock and check the timeout. */ - tv_update_date(0, 1); + clock_update_date(0, 1); hlua->run_time += now_ms - hlua->start_time; if (hlua->max_time && hlua->run_time >= hlua->max_time) { lua_pushfstring(L, "execution timeout"); @@ -1411,7 +1412,7 @@ resume_execution: /* Check if the execution timeout is expired. It it is the case, we * break the Lua execution. */ - tv_update_date(0, 1); + clock_update_date(0, 1); lua->run_time += now_ms - lua->start_time; if (lua->max_time && lua->run_time > lua->max_time) { lua_settop(lua->T, 0); /* Empty the stack. */ diff --git a/src/log.c b/src/log.c index 0e880c9d60..d15377d747 100644 --- a/src/log.c +++ b/src/log.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include diff --git a/src/sample.c b/src/sample.c index bda590875c..970dabb5bb 100644 --- a/src/sample.c +++ b/src/sample.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -39,7 +40,6 @@ #include #include #include -#include #include #include #include diff --git a/src/stats.c b/src/stats.c index 4c8ea0c8d5..da6fc363a2 100644 --- a/src/stats.c +++ b/src/stats.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include diff --git a/src/task.c b/src/task.c index 27a4ca745d..d547359655 100644 --- a/src/task.c +++ b/src/task.c @@ -18,11 +18,11 @@ #include #include #include +#include #include #include #include #include -#include #include extern struct task *process_stream(struct task *t, void *context, unsigned int state); @@ -882,7 +882,7 @@ uint sched_report_idle() } /* Update the idle time value twice a second, to be called after - * tv_update_date() when called after poll(), and currently called only by + * clock_update_date() when called after poll(), and currently called only by * sched_leaving_poll() below. It relies on to be updated to * the system time before calling poll(). */ diff --git a/src/thread.c b/src/thread.c index a3400010bc..ad5327aed2 100644 --- a/src/thread.c +++ b/src/thread.c @@ -43,11 +43,11 @@ #endif #include +#include #include #include #include #include -#include #include struct thread_info ha_thread_info[MAX_THREADS] = { }; diff --git a/src/time.c b/src/time.c index 99aed11f84..280b522b82 100644 --- a/src/time.c +++ b/src/time.c @@ -10,27 +10,11 @@ * */ -#include #include #include #include -#include -#include -THREAD_LOCAL unsigned int now_ms; /* internal date in milliseconds (may wrap) */ -THREAD_LOCAL struct timeval now; /* internal date is a monotonic function of real clock */ -THREAD_LOCAL struct timeval date; /* the real current date */ -struct timeval start_date; /* the process's start date */ -THREAD_LOCAL struct timeval before_poll; /* system date before calling poll() */ -THREAD_LOCAL struct timeval after_poll; /* system date after leaving poll() */ - -static unsigned long long now_offset; /* global offset between system time and global time */ -volatile unsigned long long global_now; /* common monotonic date between all threads (32:32) */ -volatile unsigned int global_now_ms; /* common monotonic date in milliseconds (may wrap) */ - -static THREAD_LOCAL unsigned int iso_time_sec; /* last iso time value for this thread */ -static THREAD_LOCAL char iso_time_str[34]; /* ISO time representation of gettimeofday() */ /* * adds ms to , set the result to and returns a pointer @@ -155,186 +139,6 @@ int _tv_isgt(const struct timeval *tv1, const struct timeval *tv2) return __tv_isgt(tv1, tv2); } -/* tv_update_date: sets to system time, and sets to something as - * close as possible to real time, following a monotonic function. The main - * principle consists in detecting backwards and forwards time jumps and adjust - * an offset to correct them. This function should be called once after each - * poll, and never farther apart than MAX_DELAY_MS*2. The poll's timeout should - * be passed in , and the return value in (a non-zero - * value means that we have not expired the timeout). - * - * tv_init_process_date() must have been called once first, and - * tv_init_thread_date() must also have been called once for each thread. - * - * An offset is used to adjust the current time (date), to figure a monotonic - * local time (now). The offset is not critical, as it is only updated after a - * clock jump is detected. From this point all threads will apply it to their - * locally measured time, and will then agree around a common monotonic - * global_now value that serves to further refine their local time. As it is - * not possible to atomically update a timeval, both global_now and the - * now_offset values are instead stored as 64-bit integers made of two 32 bit - * values for the tv_sec and tv_usec parts. The offset is made of two signed - * ints so that the clock can be adjusted in the two directions. - */ -void tv_update_date(int max_wait, int interrupted) -{ - struct timeval min_deadline, max_deadline, tmp_now; - unsigned int old_now_ms; - unsigned long long old_now; - unsigned long long new_now; - ullong ofs, ofs_new; - uint sec_ofs, usec_ofs; - - gettimeofday(&date, NULL); - - /* compute the minimum and maximum local date we may have reached based - * on our past date and the associated timeout. There are three possible - * extremities: - * - the new date cannot be older than before_poll - * - if not interrupted, the new date cannot be older than - * before_poll+max_wait - * - in any case the new date cannot be newer than - * before_poll+max_wait+some margin (100ms used here). - * In case of violation, we'll ignore the current date and instead - * restart from the last date we knew. - */ - _tv_ms_add(&min_deadline, &before_poll, max_wait); - _tv_ms_add(&max_deadline, &before_poll, max_wait + 100); - - ofs = HA_ATOMIC_LOAD(&now_offset); - - if (unlikely(__tv_islt(&date, &before_poll) || // big jump backwards - (!interrupted && __tv_islt(&date, &min_deadline)) || // small jump backwards - __tv_islt(&max_deadline, &date))) { // big jump forwards - if (!interrupted) - _tv_ms_add(&now, &now, max_wait); - } else { - /* The date is still within expectations. Let's apply the - * now_offset to the system date. Note: ofs if made of two - * independent signed ints. - */ - now.tv_sec = date.tv_sec + (int)(ofs >> 32); // note: may be positive or negative - now.tv_usec = date.tv_usec + (int)ofs; // note: may be positive or negative - if ((int)now.tv_usec < 0) { - now.tv_usec += 1000000; - now.tv_sec -= 1; - } else if (now.tv_usec >= 1000000) { - now.tv_usec -= 1000000; - now.tv_sec += 1; - } - } - - /* now that we have bounded the local time, let's check if it's - * realistic regarding the global date, which only moves forward, - * otherwise catch up. - */ - old_now = global_now; - old_now_ms = global_now_ms; - - do { - tmp_now.tv_sec = (unsigned int)(old_now >> 32); - tmp_now.tv_usec = old_now & 0xFFFFFFFFU; - - if (__tv_islt(&now, &tmp_now)) - now = tmp_now; - - /* now is expected to be the most accurate date, - * equal to or newer. - */ - new_now = ((ullong)now.tv_sec << 32) + (uint)now.tv_usec; - now_ms = __tv_to_ms(&now); - - /* let's try to update the global (both in timeval - * and ms forms) or loop again. - */ - } while (((new_now != old_now && !_HA_ATOMIC_CAS(&global_now, &old_now, new_now)) || - (now_ms != old_now_ms && !_HA_ATOMIC_CAS(&global_now_ms, &old_now_ms, now_ms))) && - __ha_cpu_relax()); - - /* and are now updated to the last value of global_now - * and global_now_ms, which were also monotonically updated. We can - * compute the latest offset, we don't care who writes it last, the - * variations will not break the monotonic property. - */ - - sec_ofs = now.tv_sec - date.tv_sec; - usec_ofs = now.tv_usec - date.tv_usec; - if ((int)usec_ofs < 0) { - usec_ofs += 1000000; - sec_ofs -= 1; - } - ofs_new = ((ullong)sec_ofs << 32) + usec_ofs; - if (ofs_new != ofs) - HA_ATOMIC_STORE(&now_offset, ofs_new); -} - -/* must be called once at boot to initialize some global variables */ -void tv_init_process_date() -{ - now_offset = 0; - gettimeofday(&date, NULL); - now = after_poll = before_poll = date; - global_now = ((ullong)date.tv_sec << 32) + (uint)date.tv_usec; - global_now_ms = now.tv_sec * 1000 + now.tv_usec / 1000; - ti->idle_pct = 100; - tv_update_date(0, 1); -} - -/* must be called once per thread to initialize their thread-local variables. - * Note that other threads might also be initializing and running in parallel. - */ -void tv_init_thread_date() -{ - ullong old_now; - - gettimeofday(&date, NULL); - after_poll = before_poll = date; - - old_now = _HA_ATOMIC_LOAD(&global_now); - now.tv_sec = old_now >> 32; - now.tv_usec = (uint)old_now; - ti->idle_pct = 100; - tv_update_date(0, 1); -} - -/* returns the current date as returned by gettimeofday() in ISO+microsecond - * format. It uses a thread-local static variable that the reader can consume - * for as long as it wants until next call. Thus, do not call it from a signal - * handler. If is non-0, a trailing space will be added. It will always - * return exactly 32 or 33 characters (depending on padding) and will always be - * zero-terminated, thus it will always fit into a 34 bytes buffer. - * This also always include the local timezone (in +/-HH:mm format) . - */ -char *timeofday_as_iso_us(int pad) -{ - struct timeval new_date; - struct tm tm; - const char *offset; - char c; - gettimeofday(&new_date, NULL); - if (new_date.tv_sec != iso_time_sec || !new_date.tv_sec) { - get_localtime(new_date.tv_sec, &tm); - offset = get_gmt_offset(new_date.tv_sec, &tm); - if (unlikely(strftime(iso_time_str, sizeof(iso_time_str), "%Y-%m-%dT%H:%M:%S.000000+00:00", &tm) != 32)) - strcpy(iso_time_str, "YYYY-mm-ddTHH:MM:SS.000000-00:00"); // make the failure visible but respect format. - iso_time_str[26] = offset[0]; - iso_time_str[27] = offset[1]; - iso_time_str[28] = offset[2]; - iso_time_str[30] = offset[3]; - iso_time_str[31] = offset[4]; - iso_time_sec = new_date.tv_sec; - } - /* utoa_pad adds a trailing 0 so we save the char for restore */ - c = iso_time_str[26]; - utoa_pad(new_date.tv_usec, iso_time_str + 20, 7); - iso_time_str[26] = c; - if (pad) { - iso_time_str[32] = ' '; - iso_time_str[33] = 0; - } - return iso_time_str; -} - /* * Local variables: * c-indent-level: 8 diff --git a/src/wdt.c b/src/wdt.c index f1aa3ec868..066f109ab7 100644 --- a/src/wdt.c +++ b/src/wdt.c @@ -13,12 +13,12 @@ #include #include +#include #include #include #include #include #include -#include #include