summaryrefslogtreecommitdiffstats
path: root/lib/qtime.h
diff options
context:
space:
mode:
Diffstat (limited to 'lib/qtime.h')
-rw-r--r--lib/qtime.h333
1 files changed, 333 insertions, 0 deletions
diff --git a/lib/qtime.h b/lib/qtime.h
new file mode 100644
index 00000000..df486dfd
--- /dev/null
+++ b/lib/qtime.h
@@ -0,0 +1,333 @@
+/* Quagga realtime and monotonic clock handling -- header
+ * Copyright (C) 2009 Chris Hall (GMCH), Highwayman
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * GNU Zebra 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_QTIME_H
+#define _ZEBRA_QTIME_H
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <time.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#include "zassert.h"
+#include "config.h"
+
+#ifndef Inline
+#define Inline static inline
+#endif
+
+/*==============================================================================
+ * qtime_t -- signed 64-bit integer.
+ *
+ * The various time functions work in terms of the structures:
+ *
+ * timespec -- tv_secs seconds
+ * tv_nsecs nano-seconds
+ *
+ * timeval -- tv_secs seconds
+ * tv_usecs micro-seconds
+ *
+ * Given a 64-bit integer it is much easier to do operations on a 64 bit
+ * (signed) nano-second value. That gives > 34 bits for the seconds count,
+ * and counts from zero to > 290 years.
+ */
+
+typedef int64_t qtime_t ;
+
+typedef qtime_t qtime_real_t ; /* qtime_t value, realtime time-base */
+typedef qtime_t qtime_mono_t ; /* qtime_t value, monotonic time-base */
+
+typedef qtime_t qtime_tod_t ; /* qtime_t value, timeofday time-base... */
+ /* ...just in case != CLOCK_REALTIME ! */
+
+/* A qtime_t second 123456789 -- nano-seconds */
+#define QTIME_SECOND 1000000000
+#define TIMESPEC_SECOND 1000000000
+#define TIMEVAL_SECOND 1000000
+
+/* Macro to convert time in seconds to a qtime_t */
+/* Note that the time to convert may be a float. */
+#define QTIME(s) ((qtime_t)((s) * (qtime_t)QTIME_SECOND))
+
+Inline qtime_t
+timespec2qtime(struct timespec* p_ts) ;
+
+Inline qtime_t
+timeval2qtime(struct timeval* p_tv) ;
+
+Inline struct timespec*
+qtime2timespec(struct timespec* p_ts, qtime_t qt) ;
+
+Inline struct timeval*
+qtime2timeval(struct timeval* p_tv, qtime_t qt) ;
+
+/*==============================================================================
+ * Clocks.
+ *
+ * Here is support for:
+ *
+ * * System Clock
+ *
+ * This can be read using either clock_gettime(CLOCK_REALTIME, &ts) or
+ * gettimeofday(&tv, NULL) -- which (are believed to) return the same clock,
+ * but in different units.
+ *
+ * * Monotonic Clock
+ *
+ * Using clock_gettime(CLOCK_MONOTONIC, &ts) if it is available, otherwise
+ * a manufactured equivalent using times() -- see qt_craft_monotonic().
+ */
+
+Inline qtime_real_t
+qt_get_realtime(void) ; /* clock_gettime(CLOCK_REALTIME, ...) */
+
+Inline qtime_mono_t
+qt_add_realtime(qtime_t interval) ; /* qt_get_realtime() + interval */
+
+Inline qtime_mono_t
+qt_get_monotonic(void) ; /* clock_gettime(CLOCK_MONOTONIC, ...) */
+ /* OR equivalent using times() */
+Inline qtime_mono_t
+qt_add_monotonic(qtime_t interval) ; /* qt_get_monotonic() + interval */
+Inline time_t qt_get_mono_secs(void) ;
+ /* clock_gettime(CLOCK_MONOTONIC, ...) */
+ /* OR equivalent using times() */
+
+Inline qtime_mono_t /* monotonic time from CLOCK_REALTIME */
+qt_realtime2monotonic(qtime_real_t realtime) ;
+Inline qtime_real_t /* CLOCK_REALTIME from monotonic time */
+qt_monotonic2realtime(qtime_mono_t monotonic) ;
+
+/* Function to manufacture a monotonic clock. */
+extern qtime_mono_t qt_craft_monotonic(void) ;
+extern time_t qt_craft_mono_secs(void) ;
+
+/* These are provided just in case gettimeofday() != CLOCK_REALTIME */
+Inline qtime_tod_t
+qt_get_timeofday(void) ; /* gettimeofday(&tv, NULL) */
+
+Inline qtime_tod_t
+qt_add_timeofday(qtime_t interval) ; /* qt_get_timeofday() + interval */
+
+Inline qtime_mono_t /* monotonic time from timeofday */
+qt_timeofday2monotonic(qtime_tod_t timeofday) ;
+Inline qtime_tod_t /* timeofday from monotonic time */
+qt_monotonic2timeofday(qtime_mono_t monotonic) ;
+
+/*==============================================================================
+ * Inline conversion functions
+ */
+
+/* Convert timespec to qtime_t
+ *
+ * Returns qtime_t value.
+ */
+Inline qtime_t
+timespec2qtime(struct timespec* p_ts)
+{
+ return QTIME(p_ts->tv_sec) + p_ts->tv_nsec ;
+ confirm(QTIME_SECOND == TIMESPEC_SECOND) ;
+} ;
+
+/* Convert timeval to qtime_t
+ *
+ * Returns qtime_t value.
+ */
+Inline qtime_t
+timeval2qtime(struct timeval* p_tv)
+{
+ return QTIME(p_tv->tv_sec) + (p_tv->tv_usec * 1000) ;
+ confirm(QTIME_SECOND == TIMEVAL_SECOND * 1000) ;
+} ;
+
+/* Convert qtime_t to timespec
+ *
+ * Takes address of struct timespec and returns that address.
+ */
+Inline struct timespec*
+qtime2timespec(struct timespec* p_ts, qtime_t qt)
+{
+ lldiv_t imd = lldiv(qt, QTIME_SECOND) ;
+ confirm(sizeof(long long) >= sizeof(qtime_t)) ;
+
+ p_ts->tv_sec = imd.quot ;
+ p_ts->tv_nsec = imd.rem ;
+ confirm(TIMESPEC_SECOND == QTIME_SECOND) ;
+
+ return p_ts ;
+} ;
+
+/* Convert timespec to qtime_t
+ *
+ * Takes address of struct timespec and returns that address.
+ */
+Inline struct timeval*
+qtime2timeval(struct timeval* p_tv, qtime_t qt)
+{
+ lldiv_t imd = lldiv(qt, QTIME_SECOND) ;
+ confirm(sizeof(long long) >= sizeof(qtime_t)) ;
+
+ p_tv->tv_sec = imd.quot ;
+ p_tv->tv_usec = imd.rem / 1000 ;
+ confirm(TIMEVAL_SECOND * 1000 == QTIME_SECOND) ;
+
+ return p_tv ;
+} ;
+
+/*==============================================================================
+ * Inline Clock Functions.
+ */
+
+/* Read given clock & return a qtime_t value.
+ *
+ * While possibility of error is essentially theoretical, must treat it as a
+ * FATAL error -- cannot continue with broken time value !
+ */
+
+Inline qtime_t
+qt_clock_gettime(clockid_t clock_id)
+{
+ struct timespec ts ;
+
+ if (clock_gettime(clock_id, &ts) != 0)
+ zabort_errno("clock_gettime failed") ;
+
+ return timespec2qtime(&ts) ;
+} ;
+
+/* clock_gettime(CLOCK_REALTIME, ...) -- returning qtime_t value
+ *
+ * While possibility of error is essentially theoretical, must treat it as a
+ * FATAL error -- cannot continue with broken time value !
+ */
+Inline qtime_real_t
+qt_get_realtime(void)
+{
+ return qt_clock_gettime(CLOCK_REALTIME) ;
+} ;
+
+/* qt_get_realtime() + interval
+ */
+Inline qtime_real_t
+qt_add_realtime(qtime_t interval)
+{
+ return qt_get_realtime() + interval;
+} ;
+
+/* clock_gettime(CLOCK_MONOTONIC, ...) OR qt_craft_monotonic()
+ * -- returning qtime_t value
+ *
+ * While possibility of error is essentially theoretical, must treat it as a
+ * FATAL error -- cannot continue with broken time value !
+ */
+Inline qtime_mono_t
+qt_get_monotonic(void)
+{
+#ifdef HAVE_CLOCK_MONOTONIC
+ return qt_clock_gettime(CLOCK_MONOTONIC) ;
+#else
+ return qt_craft_monotonic() ;
+#endif
+} ;
+
+/* qt_get_monotonic() + interval
+ */
+Inline qtime_mono_t
+qt_add_monotonic(qtime_t interval)
+{
+ return qt_get_monotonic() + interval;
+} ;
+
+/* clock_gettime(CLOCK_MONOTONIC, ...) OR qt_craft_monotonic()
+ * -- returning time_t value
+ *
+ * Value returned is in seconds -- for coarser grain timings.
+ *
+ * While possibility of error is essentially theoretical, must treat it as a
+ * FATAL error -- cannot continue with broken time value !
+ */
+Inline time_t
+qt_get_mono_secs(void)
+{
+#ifdef HAVE_CLOCK_MONOTONIC
+ struct timespec ts ;
+
+ if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0)
+ zabort_errno("clock_gettime failed") ;
+
+ return ts.tv_sec ;
+#else
+ return qt_craft_mono_secs() ;
+#endif
+} ;
+
+/* gettimeofday(&tv, NULL) -- returning qtime_t value
+ */
+Inline qtime_tod_t
+qt_get_timeofday(void)
+{
+ struct timeval tv ;
+ gettimeofday(&tv, NULL) ;
+ return timeval2qtime(&tv) ;
+}
+
+/* qt_get_timeofday() + interval
+ */
+Inline qtime_tod_t
+qt_add_timeofday(qtime_t interval)
+{
+ return qt_get_timeofday() + interval;
+} ;
+
+/*==============================================================================
+ * Conversion between realtime/timeofday and monotonic
+ */
+
+/* Convert a CLOCK_REALTIME time to our local monotonic time. */
+Inline qtime_mono_t
+qt_realtime2monotonic(qtime_real_t realtime)
+{
+ return qt_get_monotonic() + (realtime - qt_get_realtime()) ;
+} ;
+
+/* Convert a local monotonic time to CLOCK_REALTIME time. */
+Inline qtime_real_t
+qt_monotonic2realtime(qtime_mono_t monotonic)
+{
+ return qt_get_realtime() + (monotonic - qt_get_monotonic()) ;
+} ;
+
+/* Convert a gettimeofday() time to our local monotonic time. */
+Inline qtime_mono_t
+qt_timeofday2monotonic(qtime_tod_t timeofday)
+{
+ return qt_get_monotonic() + (timeofday - qt_get_timeofday()) ;
+} ;
+
+/* Convert a local monotonic time to gettimeofday() time. */
+Inline qtime_tod_t
+qt_monotonic2timeofday(qtime_mono_t monotonic)
+{
+ return qt_get_timeofday() + (monotonic - qt_get_monotonic()) ;
+} ;
+
+#endif /* _ZEBRA_QTIME_H */