summaryrefslogtreecommitdiffstats
path: root/lib/qtime.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/qtime.c')
-rw-r--r--lib/qtime.c128
1 files changed, 128 insertions, 0 deletions
diff --git a/lib/qtime.c b/lib/qtime.c
new file mode 100644
index 00000000..cdcf09f9
--- /dev/null
+++ b/lib/qtime.c
@@ -0,0 +1,128 @@
+/* Quagga Realtime Clock handling -- functions
+ * 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.
+ */
+
+#include <sys/times.h>
+#include <errno.h>
+
+#include "zassert.h"
+#include "qtime.h"
+
+/*==============================================================================
+ * This is a collection of functions and (in qtime.h) macros and inline
+ * functions which support system time and a monotonic clock.
+ */
+
+/*==============================================================================
+ * Replacement for CLOCK_MONOTONIC.
+ *
+ * With thanks to Joakim Tjernlund for reminding everyone of the return value
+ * from times() !
+ *
+ * times() is defined to return a value which is the time since some fixed time
+ * before the application started (or when the application started). This time
+ * is measured in units of sysconf(_SC_CLK_TCK) ticks per second.
+ *
+ * The only tricky bit is that the value returned (of type clock_t) is a
+ * signed integer, which may wrap round. It is not defined exactly how it
+ * does this... but it is generally assumed that this_sample - last_sample will
+ * give the time between the samples.
+ *
+ * The qtime_t value is in nano-seconds.
+ *
+ * The result from times() is in units of sysconf(_SC_CLK_TCK).
+ *
+ * NB: it is assumed that qt_craft_monotonic will be called often enough to
+ * ensure that it is not fooled by the clock wrapping round.
+ *
+ * Assuming that clock_t is a signed 32-bit integer, which is kept +ve,
+ * then the clock wraps round in 2^31 ticks which is:
+ *
+ * at 1,000 ticks/sec: > 24 days !
+ * at 1,000,000 ticks/sec: > 35 minutes
+ *
+ * So this should be a safe assumption -- particularly as 60, 100, 250 and
+ * 1000 ticks per second appear to be the popular options.
+ *
+ * For safety, this asserts that the value is <= 1,000,000.
+ */
+
+#ifdef GNU_LINUX
+#define TIMES_TAKES_NULL 1
+#else
+#undef TIMES_TAKES_NULL
+#endif
+
+static uint64_t monotonic = 0 ; /* monotonic clock in _SC_CLK_TCK's */
+static uint64_t last_times_sample = 0 ; /* last value returned by times() */
+
+static int64_t times_clk_tcks = 0 ; /* sysconf(_SC_CLK_TCK) */
+static qtime_t times_scale_q = 0 ; /* 10**9 / times_clk_tcks */
+static qtime_t times_scale_r = 0 ; /* 10**9 % times_clk_tcks */
+
+qtime_t
+qt_craft_monotonic(void) {
+ struct tms dummy ;
+ uint64_t this_times_sample ;
+
+ /* No errors are defined for times(), but a return of -1 is defined */
+ /* to indicate an error condition, with errno saying what it is ! */
+ /* */
+ /* The following deals carefully with this -- cannot afford for the */
+ /* clock either to jump or to get stuck ! */
+
+#ifdef TIMES_TAKES_NULL
+ this_times_sample = times(NULL) ; /* assume this saves effort ! */
+#else
+ this_times_sample = times(&dummy) ;
+#endif
+
+ if (this_times_sample == (clock_t)-1)
+ {
+ errno = 0 ;
+ this_times_sample = times(&dummy) ;
+ if (errno != 0)
+ zabort_errno("times() failed") ;
+ } ;
+
+
+ if (times_clk_tcks == 0) /* Is zero until it's initialized */
+ {
+ lldiv_t qr ;
+ confirm(sizeof(qtime_t) <= sizeof(long long int)) ;
+
+ times_clk_tcks = sysconf(_SC_CLK_TCK) ;
+ passert((times_clk_tcks > 0) && (times_clk_tcks <= 1000000)) ;
+
+ qr = lldiv(QTIME_SECOND, times_clk_tcks) ;
+ times_scale_q = qr.quot ;
+ times_scale_r = qr.rem ;
+
+ last_times_sample = this_times_sample ;
+ } ;
+
+ monotonic += (this_times_sample - last_times_sample) ;
+
+ if (times_scale_r == 0)
+ return monotonic * times_scale_q ;
+ else
+ return (monotonic * times_scale_q) +
+ ((monotonic * times_scale_r) / times_clk_tcks) ;
+} ;