From: Aurelien DARRAGON Date: Wed, 27 Aug 2025 14:14:53 +0000 (+0200) Subject: MEDIUM: stats-file: processes share the same clock source from shm-stats-file X-Git-Tag: v3.3-dev8~23 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=443e657fd60768791ef35eff0d669c0a1d399780;p=thirdparty%2Fhaproxy.git MEDIUM: stats-file: processes share the same clock source from shm-stats-file The use of the "shm-stats-file" directive now implies that all processes using the same file now share a common clock source, this is required for consistency regarding time-related operations. The clock source is stored in the shm stats file header. When the directive is set, all processes share the same clock (global_now_ms and global_now_ns both point to variables in the map), this is required for time-based counters such as freq counters to work consistently. Since all processes manipulate global clock with atomic operations exclusively during runtime, and don't systematically relies on it (thanks to local now_ms and now_ns), it is pretty much transparent. --- diff --git a/include/haproxy/stats-file-t.h b/include/haproxy/stats-file-t.h index ba0f77cb6..4e2e229a6 100644 --- a/include/haproxy/stats-file-t.h +++ b/include/haproxy/stats-file-t.h @@ -24,6 +24,9 @@ struct shm_stats_file_hdr { uint8_t major; uint8_t minor; } version; + uint global_now_ms; /* global monotonic date (ms) common to all processes using the shm */ + ullong global_now_ns; /* global monotonic date (ns) common to all processes using the shm */ + llong now_offset; /* offset applied to global monotonic date on startup */ }; struct shm_stats_file_object { diff --git a/src/stats-file.c b/src/stats-file.c index edd43f4e7..9ecdcc694 100644 --- a/src/stats-file.c +++ b/src/stats-file.c @@ -538,10 +538,50 @@ int shm_stats_file_prepare(void) memset(shm_stats_file_hdr, 0, sizeof(*shm_stats_file_hdr)); shm_stats_file_hdr->version.major = SHM_STATS_FILE_VER_MAJOR; shm_stats_file_hdr->version.minor = SHM_STATS_FILE_VER_MINOR; + + /* set global clock for the first time */ + shm_stats_file_hdr->global_now_ms = *global_now_ms; + shm_stats_file_hdr->global_now_ns = *global_now_ns; + shm_stats_file_hdr->now_offset = clock_get_now_offset(); } else if (!shm_stats_file_check_ver(shm_stats_file_hdr)) goto err_version; + /* from now on use the shared global time */ + global_now_ms = &shm_stats_file_hdr->global_now_ms; + global_now_ns = &shm_stats_file_hdr->global_now_ns; + + if (!first) { + llong adjt_offset; + + /* set adjusted offset which corresponds to the corrected offset + * relative to the initial offset stored in the shared memory instead + * of our process-local one + */ + adjt_offset = -clock_get_now_offset() + shm_stats_file_hdr->now_offset; + + /* we now rely on global_now_* from the shm, so the boot + * offset that was initially applied in clock_init_process_date() + * is no longer relevant. So we fix it by applying the one from the + * initial process instead + */ + now_ns = now_ns + adjt_offset; + start_time_ns = start_time_ns + adjt_offset; + clock_set_now_offset(shm_stats_file_hdr->now_offset); + + /* ensure global_now_* is consistent before continuing */ + clock_update_global_date(); + } + + /* now that global_now_ns is accurate, recompute precise now_offset + * if needed (in case it is dynamic when monotonic clock not available) + */ + if (!th_ctx->curr_mono_time) + clock_set_now_offset(HA_ATOMIC_LOAD(global_now_ns) - tv_to_ns(&date)); + + /* sync local and global clocks, so all clocks are consistent */ + clock_update_date(0, 1); + end: return ERR_NONE;