From 41fdbd88317ada4829f850d0fd01e23cbd9bbfb2 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Thu, 13 Oct 2022 10:46:12 +0200 Subject: [PATCH] glib-aux: rework nm_utils_timespec_to_{n,u,m}sec() helpers - add nm_utils_timespec_to_usec(). - add range checking, taken from systemd's timespec_load_nsec(). - add a unit test. --- src/libnm-glib-aux/nm-time-utils.h | 27 +++++++++++++-- .../tests/test-shared-general.c | 33 +++++++++++++++++++ 2 files changed, 57 insertions(+), 3 deletions(-) diff --git a/src/libnm-glib-aux/nm-time-utils.h b/src/libnm-glib-aux/nm-time-utils.h index 461d6845fb..05da3fd2b6 100644 --- a/src/libnm-glib-aux/nm-time-utils.h +++ b/src/libnm-glib-aux/nm-time-utils.h @@ -8,17 +8,38 @@ #include +_nm_always_inline static inline gint64 +_nm_utils_timespec_to_xsec(const struct timespec *ts, gint64 xsec_per_sec) +{ + nm_assert(ts); + + if (ts->tv_sec < 0 || ts->tv_nsec < 0) + return G_MAXINT64; + + if (ts->tv_sec > ((guint64) G_MAXINT64) || ts->tv_nsec > ((guint64) G_MAXINT64) + || ts->tv_sec >= (G_MAXINT64 - ((gint64) ts->tv_nsec)) / xsec_per_sec) + return G_MAXINT64; + + return (((gint64) ts->tv_sec) * xsec_per_sec) + + (((gint64) ts->tv_nsec) / (NM_UTILS_NSEC_PER_SEC / xsec_per_sec)); +} + static inline gint64 nm_utils_timespec_to_nsec(const struct timespec *ts) { - return (((gint64) ts->tv_sec) * ((gint64) NM_UTILS_NSEC_PER_SEC)) + ((gint64) ts->tv_nsec); + return _nm_utils_timespec_to_xsec(ts, NM_UTILS_NSEC_PER_SEC); +} + +static inline gint64 +nm_utils_timespec_to_usec(const struct timespec *ts) +{ + return _nm_utils_timespec_to_xsec(ts, NM_UTILS_USEC_PER_SEC); } static inline gint64 nm_utils_timespec_to_msec(const struct timespec *ts) { - return (((gint64) ts->tv_sec) * ((gint64) 1000)) - + (((gint64) ts->tv_nsec) / ((gint64) NM_UTILS_NSEC_PER_SEC / 1000)); + return _nm_utils_timespec_to_xsec(ts, NM_UTILS_MSEC_PER_SEC); } gint64 nm_utils_get_monotonic_timestamp_nsec(void); diff --git a/src/libnm-glib-aux/tests/test-shared-general.c b/src/libnm-glib-aux/tests/test-shared-general.c index 15033cc8d2..4131c891aa 100644 --- a/src/libnm-glib-aux/tests/test-shared-general.c +++ b/src/libnm-glib-aux/tests/test-shared-general.c @@ -90,6 +90,38 @@ test_monotonic_timestamp(void) /*****************************************************************************/ +static void +test_timespect_to(void) +{ + struct timespec ts; + int i; + + for (i = 0; i < 1000; i++) { + gint64 t_msec; + gint64 t_usec; + gint64 t_nsec; + + nmtst_rand_buf(NULL, &ts, sizeof(ts)); + ts.tv_sec = llabs(ts.tv_sec % 100000); + ts.tv_nsec = llabs(ts.tv_nsec % NM_UTILS_NSEC_PER_SEC); + + t_msec = nm_utils_timespec_to_msec(&ts); + t_usec = nm_utils_timespec_to_usec(&ts); + t_nsec = nm_utils_timespec_to_nsec(&ts); + + g_assert_cmpint(t_msec, <=, t_usec / 1000); + g_assert_cmpint(t_msec + 1, >=, t_usec / 1000); + + g_assert_cmpint(t_msec, <=, t_nsec / 1000000); + g_assert_cmpint(t_msec + 1, >=, t_nsec / 1000000); + + g_assert_cmpint(t_usec, <=, t_nsec / 1000); + g_assert_cmpint(t_usec + 1, >=, t_nsec / 1000); + } +} + +/*****************************************************************************/ + static void test_nmhash(void) { @@ -2344,6 +2376,7 @@ main(int argc, char **argv) g_test_add_func("/general/test_nm_static_assert", test_nm_static_assert); g_test_add_func("/general/test_gpid", test_gpid); g_test_add_func("/general/test_monotonic_timestamp", test_monotonic_timestamp); + g_test_add_func("/general/test_timespect_to", test_timespect_to); g_test_add_func("/general/test_nmhash", test_nmhash); g_test_add_func("/general/test_nm_make_strv", test_make_strv); g_test_add_func("/general/test_nm_strdup_int", test_nm_strdup_int);