diff --git a/src/agent/agent.c b/src/agent/agent.c index ecd7b3d5bb..5c6725c06c 100644 --- a/src/agent/agent.c +++ b/src/agent/agent.c @@ -144,7 +144,7 @@ static bool agent_check_controller_liveness(Agent *agent) { } now = get_time_micros_monotonic(); - if (now == 0) { + if (now == USEC_INFINITY) { bc_log_error("Failed to get the monotonic time"); return true; } @@ -2311,13 +2311,13 @@ static int agent_match_heartbeat(UNUSED sd_bus_message *m, void *userdata, UNUSE uint64_t now_monotonic = 0; now = get_time_micros(); - if (now == 0) { + if (now == USEC_INFINITY) { bc_log_error("Failed to get current time on heartbeat"); return 0; } now_monotonic = get_time_micros_monotonic(); - if (now_monotonic == 0) { + if (now_monotonic == USEC_INFINITY) { bc_log_error("Failed to get current monotonic time on heartbeat"); return 0; } diff --git a/src/controller/node.c b/src/controller/node.c index f8eb454346..230f80a8d7 100644 --- a/src/controller/node.c +++ b/src/controller/node.c @@ -532,13 +532,13 @@ static int node_match_heartbeat(UNUSED sd_bus_message *m, void *userdata, UNUSED uint64_t now_monotonic = 0; now = get_time_micros(); - if (now == 0) { + if (now == USEC_INFINITY) { bc_log_error("Failed to get current time on heartbeat"); return 0; } now_monotonic = get_time_micros_monotonic(); - if (now_monotonic == 0) { + if (now_monotonic == USEC_INFINITY) { bc_log_error("Failed to get current monotonic time on heartbeat"); return 0; } diff --git a/src/libbluechi/common/time-util.c b/src/libbluechi/common/time-util.c index bc7bb04a89..50b7f645dd 100644 --- a/src/libbluechi/common/time-util.c +++ b/src/libbluechi/common/time-util.c @@ -12,22 +12,18 @@ uint64_t get_time_micros() { struct timespec now; - 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; + + assert(clock_gettime(CLOCK_REALTIME, &now) == 0); + + return timespec_to_micros(&now); } uint64_t get_time_micros_monotonic() { struct timespec now; - 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; + + assert(clock_gettime(CLOCK_MONOTONIC, &now) == 0); + + return timespec_to_micros(&now); } uint64_t finalize_time_interval_micros(int64_t start_time_micros) { @@ -38,6 +34,20 @@ double micros_to_millis(uint64_t time_micros) { return (double) time_micros * microsec_to_millisec_multiplier; } +uint64_t timespec_to_micros(const struct timespec *ts) { + assert(ts); + + if (ts->tv_sec < 0 || ts->tv_nsec < 0) { + return USEC_INFINITY; + } + + if ((uint64_t) ts->tv_sec > (UINT64_MAX - (ts->tv_nsec / NSEC_PER_USEC)) / USEC_PER_SEC) { + return USEC_INFINITY; + } + + return (uint64_t) ts->tv_sec * USEC_PER_SEC + (uint64_t) ts->tv_nsec / NSEC_PER_USEC; +} + 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..164ee1e097 100644 --- a/src/libbluechi/common/time-util.h +++ b/src/libbluechi/common/time-util.h @@ -9,6 +9,8 @@ #include #include +#define USEC_INFINITY UINT64_MAX + static const uint64_t sec_to_microsec_multiplier = 1000000; static const double microsec_to_millisec_multiplier = 1e-3; static const double nanosec_to_microsec_multiplier = 1e-3; @@ -19,5 +21,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(const struct timespec *ts); 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..c04de8ec0b --- /dev/null +++ b/src/libbluechi/test/common/time-util/timespec_to_micros_test.c @@ -0,0 +1,72 @@ +/* + * Copyright Contributors to the Eclipse BlueChi project + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#include +#include +#include + +#include "libbluechi/common/protocol.h" +#include "libbluechi/common/time-util.h" + +int main() { + struct timespec ts = { 0, 0 }; + + assert(timespec_to_micros(&ts) == 0); + + ts.tv_sec = -1; + ts.tv_nsec = 0; + assert(timespec_to_micros(&ts) == USEC_INFINITY); + + ts.tv_sec = 0; + ts.tv_nsec = -1; + assert(timespec_to_micros(&ts) == USEC_INFINITY); + + ts.tv_sec = 0; + ts.tv_nsec = 1234; + assert(timespec_to_micros(&ts) == 1); + + ts.tv_sec = 5678; + ts.tv_nsec = 0; + assert(timespec_to_micros(&ts) == 5678000000); + + ts.tv_sec = 123; + ts.tv_nsec = 4567890; + assert(timespec_to_micros(&ts) == 123004567); + + if (LONG_MAX < UINT64_MAX / USEC_PER_SEC) { + ts.tv_sec = LONG_MAX; + ts.tv_nsec = 999999999; + assert(timespec_to_micros(&ts) == (uint64_t) LONG_MAX * USEC_PER_SEC + 999999); + } + +#if defined(__x86_64__) || defined(__aarch64__) + ts.tv_sec = LONG_MAX; + ts.tv_nsec = 0; + assert(timespec_to_micros(&ts) == USEC_INFINITY); + + ts.tv_sec = UINT64_MAX / USEC_PER_SEC; + ts.tv_nsec = 0; + assert(timespec_to_micros(&ts) == 18446744073709000000ULL); + + ts.tv_sec = UINT64_MAX / USEC_PER_SEC; + ts.tv_nsec = 551614999; + assert(timespec_to_micros(&ts) == 18446744073709551614ULL); + + ts.tv_sec = UINT64_MAX / USEC_PER_SEC; + ts.tv_nsec = 551615000; + assert(timespec_to_micros(&ts) == UINT64_MAX); + + ts.tv_sec = UINT64_MAX / USEC_PER_SEC; + ts.tv_nsec = 551616000; + assert(timespec_to_micros(&ts) == USEC_INFINITY); + + ts.tv_sec = UINT64_MAX / USEC_PER_SEC + 1; + ts.tv_nsec = 0; + assert(timespec_to_micros(&ts) == USEC_INFINITY); +#endif + + return EXIT_SUCCESS; +}