diff options
Diffstat (limited to 'src/NetworkManagerUtils.c')
-rw-r--r-- | src/NetworkManagerUtils.c | 53 |
1 files changed, 48 insertions, 5 deletions
diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c index 0f957814d3..ae2e83e482 100644 --- a/src/NetworkManagerUtils.c +++ b/src/NetworkManagerUtils.c @@ -1818,15 +1818,15 @@ 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) { - static int clock_mode = 0; - gboolean first_time = FALSE; + int clock_mode = 0; int err = 0; - switch (clock_mode) { + switch (monotonic_timestamp_clock_mode) { case 0: /* the clock is not yet initialized (first run) */ err = clock_gettime (CLOCK_BOOTTIME, tp); @@ -1835,7 +1835,6 @@ monotonic_timestamp_get (struct timespec *tp) err = clock_gettime (CLOCK_MONOTONIC, tp); } else clock_mode = 1; - first_time = TRUE; break; case 1: /* default, return CLOCK_BOOTTIME */ @@ -1851,7 +1850,7 @@ monotonic_timestamp_get (struct timespec *tp) g_assert (err == 0); (void)err; g_assert (tp->tv_nsec >= 0 && tp->tv_nsec < NM_UTILS_NS_PER_SECOND); - if (G_LIKELY (!first_time)) + if (G_LIKELY (clock_mode == 0)) return; /* Calculate an offset for the time stamp. @@ -1868,6 +1867,7 @@ monotonic_timestamp_get (struct timespec *tp) * wraps (~68 years). **/ monotonic_timestamp_offset_sec = (- ((gint64) tp->tv_sec)) + 1; + monotonic_timestamp_clock_mode = clock_mode; if (nm_logging_enabled (LOGL_DEBUG, LOGD_CORE)) { time_t now = time (NULL); @@ -2232,6 +2232,49 @@ 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/" |