From a6add8175a150f9bf64ac0b27064dc0d736aea6a Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Wed, 17 Oct 2018 14:09:13 +0200 Subject: shared: move nm_utils_get_monotonic_timestamp*() to shared/nm-utils. This is independent functionality that only depends on linux API and glib. Note how "nm-logging" uses this for getting the timestamps. This makes "nm-logging.c" itself dependen on "src/nm-core-utils.c", for little reason. --- Makefile.am | 3 + shared/meson.build | 2 + shared/nm-utils/nm-time-utils.c | 227 ++++++++++++++++++++++++++++++++++++++++ shared/nm-utils/nm-time-utils.h | 45 ++++++++ src/meson.build | 2 + src/nm-core-utils.c | 200 ----------------------------------- src/nm-core-utils.h | 19 +--- src/nm-logging.c | 4 +- 8 files changed, 283 insertions(+), 219 deletions(-) create mode 100644 shared/nm-utils/nm-time-utils.c create mode 100644 shared/nm-utils/nm-time-utils.h diff --git a/Makefile.am b/Makefile.am index 5c1af3a0e2..da4c229d3f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1577,6 +1577,9 @@ EXTRA_DIST += \ src_libNetworkManagerBase_la_CPPFLAGS = $(src_cppflags) src_libNetworkManagerBase_la_SOURCES = \ + \ + shared/nm-utils/nm-time-utils.c \ + shared/nm-utils/nm-time-utils.h \ \ src/nm-core-utils.c \ src/nm-core-utils.h \ diff --git a/shared/meson.build b/shared/meson.build index edac3bb9e1..9afc9a6d56 100644 --- a/shared/meson.build +++ b/shared/meson.build @@ -81,6 +81,8 @@ shared_nm_test_utils_impl_c = files('nm-test-utils-impl.c') shared_nm_utils_nm_vpn_plugin_utils_c = files('nm-utils/nm-vpn-plugin-utils.c') +shared_files_time_utils = files('nm-utils/nm-time-utils.c') + shared_files_libnm_core = files(''' nm-utils/c-list-util.c nm-utils/nm-dedup-multi.c diff --git a/shared/nm-utils/nm-time-utils.c b/shared/nm-utils/nm-time-utils.c new file mode 100644 index 0000000000..26b982246b --- /dev/null +++ b/shared/nm-utils/nm-time-utils.c @@ -0,0 +1,227 @@ +/* NetworkManager -- Network link manager + * + * 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; either + * version 2 of the License, or (at your option) any later version. + * + * 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. + * + * (C) Copyright 2018 Red Hat, Inc. + */ + +#include "nm-default.h" + +#include "nm-time-utils.h" + +/*****************************************************************************/ + +static gint64 monotonic_timestamp_offset_sec; +static int monotonic_timestamp_clock_mode = 0; + +static void +monotonic_timestamp_get (struct timespec *tp) +{ + int clock_mode = 0; + int err = 0; + + switch (monotonic_timestamp_clock_mode) { + case 0: + /* the clock is not yet initialized (first run) */ + err = clock_gettime (CLOCK_BOOTTIME, tp); + if (err == -1 && errno == EINVAL) { + clock_mode = 2; + err = clock_gettime (CLOCK_MONOTONIC, tp); + } else + clock_mode = 1; + break; + case 1: + /* default, return CLOCK_BOOTTIME */ + err = clock_gettime (CLOCK_BOOTTIME, tp); + break; + case 2: + /* fallback, return CLOCK_MONOTONIC. Kernels prior to 2.6.39 + * (released on 18 May, 2011) don't support CLOCK_BOOTTIME. */ + err = clock_gettime (CLOCK_MONOTONIC, tp); + break; + } + + g_assert (err == 0); (void)err; + g_assert (tp->tv_nsec >= 0 && tp->tv_nsec < NM_UTILS_NS_PER_SECOND); + + if (G_LIKELY (clock_mode == 0)) + return; + + /* Calculate an offset for the time stamp. + * + * We always want positive values, because then we can initialize + * a timestamp with 0 and be sure, that it will be less then any + * value nm_utils_get_monotonic_timestamp_*() might return. + * For this to be true also for nm_utils_get_monotonic_timestamp_s() at + * early boot, we have to shift the timestamp to start counting at + * least from 1 second onward. + * + * Another advantage of shifting is, that this way we make use of the whole 31 bit + * range of signed int, before the time stamp for nm_utils_get_monotonic_timestamp_s() + * wraps (~68 years). + **/ + monotonic_timestamp_offset_sec = (- ((gint64) tp->tv_sec)) + 1; + monotonic_timestamp_clock_mode = clock_mode; + + _nm_utils_monotonic_timestamp_initialized (tp, monotonic_timestamp_offset_sec, clock_mode == 1); +} + +/** + * nm_utils_get_monotonic_timestamp_ns: + * + * Returns: a monotonically increasing time stamp in nanoseconds, + * starting at an unspecified offset. See clock_gettime(), %CLOCK_BOOTTIME. + * + * The returned value will start counting at an undefined point + * in the past and will always be positive. + * + * All the nm_utils_get_monotonic_timestamp_*s functions return the same + * timestamp but in different scales (nsec, usec, msec, sec). + **/ +gint64 +nm_utils_get_monotonic_timestamp_ns (void) +{ + struct timespec tp = { 0 }; + + monotonic_timestamp_get (&tp); + + /* Although the result will always be positive, we return a signed + * integer, which makes it easier to calculate time differences (when + * you want to subtract signed values). + **/ + return (((gint64) tp.tv_sec) + monotonic_timestamp_offset_sec) * NM_UTILS_NS_PER_SECOND + + tp.tv_nsec; +} + +/** + * nm_utils_get_monotonic_timestamp_us: + * + * Returns: a monotonically increasing time stamp in microseconds, + * starting at an unspecified offset. See clock_gettime(), %CLOCK_BOOTTIME. + * + * The returned value will start counting at an undefined point + * in the past and will always be positive. + * + * All the nm_utils_get_monotonic_timestamp_*s functions return the same + * timestamp but in different scales (nsec, usec, msec, sec). + **/ +gint64 +nm_utils_get_monotonic_timestamp_us (void) +{ + struct timespec tp = { 0 }; + + monotonic_timestamp_get (&tp); + + /* Although the result will always be positive, we return a signed + * integer, which makes it easier to calculate time differences (when + * you want to subtract signed values). + **/ + return (((gint64) tp.tv_sec) + monotonic_timestamp_offset_sec) * ((gint64) G_USEC_PER_SEC) + + (tp.tv_nsec / (NM_UTILS_NS_PER_SECOND/G_USEC_PER_SEC)); +} + +/** + * nm_utils_get_monotonic_timestamp_ms: + * + * Returns: a monotonically increasing time stamp in milliseconds, + * starting at an unspecified offset. See clock_gettime(), %CLOCK_BOOTTIME. + * + * The returned value will start counting at an undefined point + * in the past and will always be positive. + * + * All the nm_utils_get_monotonic_timestamp_*s functions return the same + * timestamp but in different scales (nsec, usec, msec, sec). + **/ +gint64 +nm_utils_get_monotonic_timestamp_ms (void) +{ + struct timespec tp = { 0 }; + + monotonic_timestamp_get (&tp); + + /* Although the result will always be positive, we return a signed + * integer, which makes it easier to calculate time differences (when + * you want to subtract signed values). + **/ + return (((gint64) tp.tv_sec) + monotonic_timestamp_offset_sec) * ((gint64) 1000) + + (tp.tv_nsec / (NM_UTILS_NS_PER_SECOND/1000)); +} + +/** + * nm_utils_get_monotonic_timestamp_s: + * + * Returns: nm_utils_get_monotonic_timestamp_ms() in seconds (throwing + * away sub second parts). The returned value will always be positive. + * + * This value wraps after roughly 68 years which should be fine for any + * practical purpose. + * + * All the nm_utils_get_monotonic_timestamp_*s functions return the same + * timestamp but in different scales (nsec, usec, msec, sec). + **/ +gint32 +nm_utils_get_monotonic_timestamp_s (void) +{ + struct timespec tp = { 0 }; + + monotonic_timestamp_get (&tp); + return (((gint64) tp.tv_sec) + monotonic_timestamp_offset_sec); +} + +/** + * nm_utils_monotonic_timestamp_as_boottime: + * @timestamp: the monotonic-timestamp that should be converted into CLOCK_BOOTTIME. + * @timestamp_ns_per_tick: How many nano seconds make one unit of @timestamp? E.g. if + * @timestamp is in unit seconds, pass %NM_UTILS_NS_PER_SECOND; @timestamp in nano + * seconds, pass 1; @timestamp in milli seconds, pass %NM_UTILS_NS_PER_SECOND/1000; etc. + * + * Returns: the monotonic-timestamp as CLOCK_BOOTTIME, as returned by clock_gettime(). + * The unit is the same as the passed in @timestamp basd on @timestamp_ns_per_tick. + * E.g. if you passed @timestamp in as seconds, it will return boottime in seconds. + * If @timestamp is a non-positive, it returns -1. Note that a (valid) monotonic-timestamp + * is always positive. + * + * On older kernels that don't support CLOCK_BOOTTIME, the returned time is instead CLOCK_MONOTONIC. + **/ +gint64 +nm_utils_monotonic_timestamp_as_boottime (gint64 timestamp, gint64 timestamp_ns_per_tick) +{ + gint64 offset; + + /* only support ns-per-tick being a multiple of 10. */ + g_return_val_if_fail (timestamp_ns_per_tick == 1 + || (timestamp_ns_per_tick > 0 && + timestamp_ns_per_tick <= NM_UTILS_NS_PER_SECOND && + timestamp_ns_per_tick % 10 == 0), + -1); + + /* Check that the timestamp is in a valid range. */ + g_return_val_if_fail (timestamp >= 0, -1); + + /* if the caller didn't yet ever fetch a monotonic-timestamp, he cannot pass any meaningful + * value (because he has no idea what these timestamps would be). That would be a bug. */ + g_return_val_if_fail (monotonic_timestamp_clock_mode != 0, -1); + + /* calculate the offset of monotonic-timestamp to boottime. offset_s is <= 1. */ + offset = monotonic_timestamp_offset_sec * (NM_UTILS_NS_PER_SECOND / timestamp_ns_per_tick); + + /* check for overflow. */ + g_return_val_if_fail (offset > 0 || timestamp < G_MAXINT64 + offset, G_MAXINT64); + + return timestamp - offset; +} + + diff --git a/shared/nm-utils/nm-time-utils.h b/shared/nm-utils/nm-time-utils.h new file mode 100644 index 0000000000..7e4f4f25f7 --- /dev/null +++ b/shared/nm-utils/nm-time-utils.h @@ -0,0 +1,45 @@ +/* NetworkManager -- Network link manager + * + * 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; either + * version 2 of the License, or (at your option) any later version. + * + * 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. + * + * (C) Copyright 2018 Red Hat, Inc. + */ + +#ifndef __NM_TIME_UTILS_H__ +#define __NM_TIME_UTILS_H__ + +gint64 nm_utils_get_monotonic_timestamp_ns (void); +gint64 nm_utils_get_monotonic_timestamp_us (void); +gint64 nm_utils_get_monotonic_timestamp_ms (void); +gint32 nm_utils_get_monotonic_timestamp_s (void); +gint64 nm_utils_monotonic_timestamp_as_boottime (gint64 timestamp, gint64 timestamp_ticks_per_ns); + +static inline gint64 +nm_utils_get_monotonic_timestamp_ns_cached (gint64 *cache_now) +{ + return (*cache_now) + ?: (*cache_now = nm_utils_get_monotonic_timestamp_ns ()); +} + +struct timespec; + +/* this function must be implemented to handle the notification when + * the first monotonic-timestamp is fetched. */ +extern void _nm_utils_monotonic_timestamp_initialized (const struct timespec *tp, + gint64 offset_sec, + gboolean is_boottime); + +#endif /* __NM_TIME_UTILS_H__ */ diff --git a/src/meson.build b/src/meson.build index 87c576714d..f293f299b5 100644 --- a/src/meson.build +++ b/src/meson.build @@ -45,6 +45,8 @@ sources = files( 'nm-logging.c' ) +sources += shared_files_time_utils + deps = [ libsystemd_dep, libudev_dep, diff --git a/src/nm-core-utils.c b/src/nm-core-utils.c index 20d84e4627..50f127c090 100644 --- a/src/nm-core-utils.c +++ b/src/nm-core-utils.c @@ -1879,163 +1879,6 @@ nm_utils_cmp_connection_by_autoconnect_priority (NMConnection *a, NMConnection * /*****************************************************************************/ -static gint64 monotonic_timestamp_offset_sec; -static int monotonic_timestamp_clock_mode = 0; - -static void -monotonic_timestamp_get (struct timespec *tp) -{ - int clock_mode = 0; - int err = 0; - - switch (monotonic_timestamp_clock_mode) { - case 0: - /* the clock is not yet initialized (first run) */ - err = clock_gettime (CLOCK_BOOTTIME, tp); - if (err == -1 && errno == EINVAL) { - clock_mode = 2; - err = clock_gettime (CLOCK_MONOTONIC, tp); - } else - clock_mode = 1; - break; - case 1: - /* default, return CLOCK_BOOTTIME */ - err = clock_gettime (CLOCK_BOOTTIME, tp); - break; - case 2: - /* fallback, return CLOCK_MONOTONIC. Kernels prior to 2.6.39 - * (released on 18 May, 2011) don't support CLOCK_BOOTTIME. */ - err = clock_gettime (CLOCK_MONOTONIC, tp); - break; - } - - g_assert (err == 0); (void)err; - g_assert (tp->tv_nsec >= 0 && tp->tv_nsec < NM_UTILS_NS_PER_SECOND); - - if (G_LIKELY (clock_mode == 0)) - return; - - /* Calculate an offset for the time stamp. - * - * We always want positive values, because then we can initialize - * a timestamp with 0 and be sure, that it will be less then any - * value nm_utils_get_monotonic_timestamp_*() might return. - * For this to be true also for nm_utils_get_monotonic_timestamp_s() at - * early boot, we have to shift the timestamp to start counting at - * least from 1 second onward. - * - * Another advantage of shifting is, that this way we make use of the whole 31 bit - * range of signed int, before the time stamp for nm_utils_get_monotonic_timestamp_s() - * wraps (~68 years). - **/ - monotonic_timestamp_offset_sec = (- ((gint64) tp->tv_sec)) + 1; - monotonic_timestamp_clock_mode = clock_mode; - - _nm_utils_monotonic_timestamp_initialized (tp, monotonic_timestamp_offset_sec, clock_mode == 1); -} - -/** - * nm_utils_get_monotonic_timestamp_ns: - * - * Returns: a monotonically increasing time stamp in nanoseconds, - * starting at an unspecified offset. See clock_gettime(), %CLOCK_BOOTTIME. - * - * The returned value will start counting at an undefined point - * in the past and will always be positive. - * - * All the nm_utils_get_monotonic_timestamp_*s functions return the same - * timestamp but in different scales (nsec, usec, msec, sec). - **/ -gint64 -nm_utils_get_monotonic_timestamp_ns (void) -{ - struct timespec tp = { 0 }; - - monotonic_timestamp_get (&tp); - - /* Although the result will always be positive, we return a signed - * integer, which makes it easier to calculate time differences (when - * you want to subtract signed values). - **/ - return (((gint64) tp.tv_sec) + monotonic_timestamp_offset_sec) * NM_UTILS_NS_PER_SECOND + - tp.tv_nsec; -} - -/** - * nm_utils_get_monotonic_timestamp_us: - * - * Returns: a monotonically increasing time stamp in microseconds, - * starting at an unspecified offset. See clock_gettime(), %CLOCK_BOOTTIME. - * - * The returned value will start counting at an undefined point - * in the past and will always be positive. - * - * All the nm_utils_get_monotonic_timestamp_*s functions return the same - * timestamp but in different scales (nsec, usec, msec, sec). - **/ -gint64 -nm_utils_get_monotonic_timestamp_us (void) -{ - struct timespec tp = { 0 }; - - monotonic_timestamp_get (&tp); - - /* Although the result will always be positive, we return a signed - * integer, which makes it easier to calculate time differences (when - * you want to subtract signed values). - **/ - return (((gint64) tp.tv_sec) + monotonic_timestamp_offset_sec) * ((gint64) G_USEC_PER_SEC) + - (tp.tv_nsec / (NM_UTILS_NS_PER_SECOND/G_USEC_PER_SEC)); -} - -/** - * nm_utils_get_monotonic_timestamp_ms: - * - * Returns: a monotonically increasing time stamp in milliseconds, - * starting at an unspecified offset. See clock_gettime(), %CLOCK_BOOTTIME. - * - * The returned value will start counting at an undefined point - * in the past and will always be positive. - * - * All the nm_utils_get_monotonic_timestamp_*s functions return the same - * timestamp but in different scales (nsec, usec, msec, sec). - **/ -gint64 -nm_utils_get_monotonic_timestamp_ms (void) -{ - struct timespec tp = { 0 }; - - monotonic_timestamp_get (&tp); - - /* Although the result will always be positive, we return a signed - * integer, which makes it easier to calculate time differences (when - * you want to subtract signed values). - **/ - return (((gint64) tp.tv_sec) + monotonic_timestamp_offset_sec) * ((gint64) 1000) + - (tp.tv_nsec / (NM_UTILS_NS_PER_SECOND/1000)); -} - -/** - * nm_utils_get_monotonic_timestamp_s: - * - * Returns: nm_utils_get_monotonic_timestamp_ms() in seconds (throwing - * away sub second parts). The returned value will always be positive. - * - * This value wraps after roughly 68 years which should be fine for any - * practical purpose. - * - * All the nm_utils_get_monotonic_timestamp_*s functions return the same - * timestamp but in different scales (nsec, usec, msec, sec). - **/ -gint32 -nm_utils_get_monotonic_timestamp_s (void) -{ - struct timespec tp = { 0 }; - - monotonic_timestamp_get (&tp); - return (((gint64) tp.tv_sec) + monotonic_timestamp_offset_sec); -} - typedef struct { const char *name; @@ -2315,49 +2158,6 @@ out: g_array_free (sorted_hashes, TRUE); } -/** - * nm_utils_monotonic_timestamp_as_boottime: - * @timestamp: the monotonic-timestamp that should be converted into CLOCK_BOOTTIME. - * @timestamp_ns_per_tick: How many nano seconds make one unit of @timestamp? E.g. if - * @timestamp is in unit seconds, pass %NM_UTILS_NS_PER_SECOND; @timestamp in nano - * seconds, pass 1; @timestamp in milli seconds, pass %NM_UTILS_NS_PER_SECOND/1000; etc. - * - * Returns: the monotonic-timestamp as CLOCK_BOOTTIME, as returned by clock_gettime(). - * The unit is the same as the passed in @timestamp basd on @timestamp_ns_per_tick. - * E.g. if you passed @timestamp in as seconds, it will return boottime in seconds. - * If @timestamp is a non-positive, it returns -1. Note that a (valid) monotonic-timestamp - * is always positive. - * - * On older kernels that don't support CLOCK_BOOTTIME, the returned time is instead CLOCK_MONOTONIC. - **/ -gint64 -nm_utils_monotonic_timestamp_as_boottime (gint64 timestamp, gint64 timestamp_ns_per_tick) -{ - gint64 offset; - - /* only support ns-per-tick being a multiple of 10. */ - g_return_val_if_fail (timestamp_ns_per_tick == 1 - || (timestamp_ns_per_tick > 0 && - timestamp_ns_per_tick <= NM_UTILS_NS_PER_SECOND && - timestamp_ns_per_tick % 10 == 0), - -1); - - /* Check that the timestamp is in a valid range. */ - g_return_val_if_fail (timestamp >= 0, -1); - - /* if the caller didn't yet ever fetch a monotonic-timestamp, he cannot pass any meaningful - * value (because he has no idea what these timestamps would be). That would be a bug. */ - g_return_val_if_fail (monotonic_timestamp_clock_mode != 0, -1); - - /* calculate the offset of monotonic-timestamp to boottime. offset_s is <= 1. */ - offset = monotonic_timestamp_offset_sec * (NM_UTILS_NS_PER_SECOND / timestamp_ns_per_tick); - - /* check for overflow. */ - g_return_val_if_fail (offset > 0 || timestamp < G_MAXINT64 + offset, G_MAXINT64); - - return timestamp - offset; -} - #define IPV6_PROPERTY_DIR "/proc/sys/net/ipv6/conf/" #define IPV4_PROPERTY_DIR "/proc/sys/net/ipv4/conf/" G_STATIC_ASSERT (sizeof (IPV4_PROPERTY_DIR) == sizeof (IPV6_PROPERTY_DIR)); diff --git a/src/nm-core-utils.h b/src/nm-core-utils.h index 6800f070a1..2591fd28bb 100644 --- a/src/nm-core-utils.h +++ b/src/nm-core-utils.h @@ -27,6 +27,8 @@ #include "nm-connection.h" +#include "nm-utils/nm-time-utils.h" + /*****************************************************************************/ #define NM_PLATFORM_LIFETIME_PERMANENT G_MAXUINT32 @@ -240,23 +242,6 @@ void nm_utils_log_connection_diff (NMConnection *connection, const char *prefix, const char *dbus_path); -gint64 nm_utils_get_monotonic_timestamp_ns (void); -gint64 nm_utils_get_monotonic_timestamp_us (void); -gint64 nm_utils_get_monotonic_timestamp_ms (void); -gint32 nm_utils_get_monotonic_timestamp_s (void); -gint64 nm_utils_monotonic_timestamp_as_boottime (gint64 timestamp, gint64 timestamp_ticks_per_ns); - -static inline gint64 -nm_utils_get_monotonic_timestamp_ns_cached (gint64 *cache_now) -{ - return (*cache_now) - ?: (*cache_now = nm_utils_get_monotonic_timestamp_ns ()); -} - -void _nm_utils_monotonic_timestamp_initialized (const struct timespec *tp, - gint64 offset_sec, - gboolean is_boottime); - gboolean nm_utils_is_valid_path_component (const char *name); const char *NM_ASSERT_VALID_PATH_COMPONENT (const char *name); diff --git a/src/nm-logging.c b/src/nm-logging.c index f80f28d934..e8bb7025cc 100644 --- a/src/nm-logging.c +++ b/src/nm-logging.c @@ -746,8 +746,8 @@ _nm_log_impl (const char *file, void _nm_utils_monotonic_timestamp_initialized (const struct timespec *tp, - gint64 offset_sec, - gboolean is_boottime) + gint64 offset_sec, + gboolean is_boottime) { if (nm_logging_enabled (LOGL_DEBUG, LOGD_CORE)) { time_t now = time (NULL); -- cgit v1.2.1