From 549c1457b001fc96d7b6c7a472b84576e375694d Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Tue, 8 Oct 2024 17:50:27 +0900 Subject: [PATCH] Add timespec_to_micros in time-util The function timespec_to_micros converts the time stored in a struct timespec into microseconds (uint64_t type). Signed-off-by: Joonyoung Shim --- src/libbluechi/common/time-util.c | 25 ++++++-- src/libbluechi/common/time-util.h | 1 + .../test/common/time-util/meson.build | 1 + .../time-util/timespec_to_micros_test.c | 59 +++++++++++++++++++ 4 files changed, 80 insertions(+), 6 deletions(-) create mode 100644 src/libbluechi/test/common/time-util/timespec_to_micros_test.c diff --git a/src/libbluechi/common/time-util.c b/src/libbluechi/common/time-util.c index bc7bb04a89..a1e8fdc6c2 100644 --- a/src/libbluechi/common/time-util.c +++ b/src/libbluechi/common/time-util.c @@ -15,9 +15,7 @@ uint64_t get_time_micros() { if (clock_gettime(CLOCK_REALTIME, &now) < 0) { return 0; } - uint64_t now_micros = now.tv_sec * sec_to_microsec_multiplier + - (uint64_t) ((double) now.tv_nsec * nanosec_to_microsec_multiplier); - return now_micros; + return timespec_to_micros(now); } uint64_t get_time_micros_monotonic() { @@ -25,9 +23,7 @@ uint64_t get_time_micros_monotonic() { if (clock_gettime(CLOCK_MONOTONIC, &now) < 0) { return 0; } - uint64_t now_micros = now.tv_sec * sec_to_microsec_multiplier + - (uint64_t) ((double) now.tv_nsec * nanosec_to_microsec_multiplier); - return now_micros; + return timespec_to_micros(now); } uint64_t finalize_time_interval_micros(int64_t start_time_micros) { @@ -38,6 +34,23 @@ double micros_to_millis(uint64_t time_micros) { return (double) time_micros * microsec_to_millisec_multiplier; } +uint64_t timespec_to_micros(struct timespec time) { + uint64_t sec_micros = 0; + uint64_t nsec_micros = 0; + + if ((uint64_t) time.tv_sec > UINT64_MAX / sec_to_microsec_multiplier) { + return 0; + } + + sec_micros = time.tv_sec * sec_to_microsec_multiplier; + nsec_micros = (uint64_t) ((double) time.tv_nsec * nanosec_to_microsec_multiplier); + if (sec_micros > UINT64_MAX - nsec_micros) { + return 0; + } + + return sec_micros + nsec_micros; +} + char *get_formatted_log_timestamp() { struct timespec now; int r = 0; diff --git a/src/libbluechi/common/time-util.h b/src/libbluechi/common/time-util.h index 8f907804e6..3afd339018 100644 --- a/src/libbluechi/common/time-util.h +++ b/src/libbluechi/common/time-util.h @@ -19,5 +19,6 @@ uint64_t get_time_micros(); uint64_t get_time_micros_monotonic(); uint64_t finalize_time_interval_micros(int64_t start_time_micros); double micros_to_millis(uint64_t time_micros); +uint64_t timespec_to_micros(struct timespec time); char *get_formatted_log_timestamp(); char *get_formatted_log_timestamp_for_timespec(struct timespec time, bool is_gmt); diff --git a/src/libbluechi/test/common/time-util/meson.build b/src/libbluechi/test/common/time-util/meson.build index 0fd36967b9..121d2370ab 100644 --- a/src/libbluechi/test/common/time-util/meson.build +++ b/src/libbluechi/test/common/time-util/meson.build @@ -6,6 +6,7 @@ network_src = [ 'get_log_timestamp', 'micros_to_millis_test', + 'timespec_to_micros_test', ] foreach src : network_src diff --git a/src/libbluechi/test/common/time-util/timespec_to_micros_test.c b/src/libbluechi/test/common/time-util/timespec_to_micros_test.c new file mode 100644 index 0000000000..6a4573cecd --- /dev/null +++ b/src/libbluechi/test/common/time-util/timespec_to_micros_test.c @@ -0,0 +1,59 @@ +/* + * Copyright Contributors to the Eclipse BlueChi project + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#include +#include +#include + +#include "libbluechi/common/time-util.h" + +int main() { + struct timespec time = { 0, 0 }; + + assert(timespec_to_micros(time) == 0); + + time.tv_sec = 0; + time.tv_nsec = 1234; + assert(timespec_to_micros(time) == 1); + + time.tv_sec = 5678; + time.tv_nsec = 0; + assert(timespec_to_micros(time) == 5678000000); + + time.tv_sec = 123; + time.tv_nsec = 4567890; + assert(timespec_to_micros(time) == 123004567); + + if (LONG_MAX < UINT64_MAX / sec_to_microsec_multiplier) { + time.tv_sec = LONG_MAX; + time.tv_nsec = 999999999; + assert(timespec_to_micros(time) == LONG_MAX * sec_to_microsec_multiplier + 999999); + } + +#if defined(__x86_64__) || defined(__aarch64__) + time.tv_sec = LONG_MAX; + time.tv_nsec = 0; + assert(timespec_to_micros(time) == 0); + + time.tv_sec = UINT64_MAX / sec_to_microsec_multiplier; + time.tv_nsec = 0; + assert(timespec_to_micros(time) == 18446744073709000000ULL); + + time.tv_sec = UINT64_MAX / sec_to_microsec_multiplier; + time.tv_nsec = 551615000; + assert(timespec_to_micros(time) == UINT64_MAX); + + time.tv_sec = UINT64_MAX / sec_to_microsec_multiplier; + time.tv_nsec = 551616000; + assert(timespec_to_micros(time) == 0); + + time.tv_sec = UINT64_MAX / sec_to_microsec_multiplier + 1; + time.tv_nsec = 0; + assert(timespec_to_micros(time) == 0); +#endif + + return EXIT_SUCCESS; +}