summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/Makefile.am3
-rw-r--r--lib/bfd.c2
-rw-r--r--lib/log.c1
-rw-r--r--lib/monotime.h77
-rw-r--r--lib/thread.c200
-rw-r--r--lib/thread.h11
6 files changed, 106 insertions, 188 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am
index f2c076c475..5dd38ee45a 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -46,7 +46,8 @@ pkginclude_HEADERS = \
ptm_lib.h csv.h bfd.h vrf.h ns.h systemd.h bitfield.h \
fifo.h memory_vty.h mpls.h imsg.h openbsd-queue.h openbsd-tree.h \
skiplist.h qobj.h wheel.h \
- event_counter.h
+ event_counter.h \
+ monotime.h
noinst_HEADERS = \
plist_int.h
diff --git a/lib/bfd.c b/lib/bfd.c
index 5db08fea60..a5edaea217 100644
--- a/lib/bfd.c
+++ b/lib/bfd.c
@@ -362,7 +362,7 @@ bfd_last_update (time_t last_update, char *buf, size_t len)
}
/* Get current time. */
- quagga_gettime(QUAGGA_CLK_MONOTONIC, &tv);
+ monotime(&tv);
curr = tv.tv_sec;
diff = curr - last_update;
tm = gmtime (&diff);
diff --git a/lib/log.c b/lib/log.c
index 13592a0240..b8e505f347 100644
--- a/lib/log.c
+++ b/lib/log.c
@@ -118,7 +118,6 @@ quagga_timestamp(int timestamp_precision, char *buf, size_t buflen)
} cache;
struct timeval clock;
- /* would it be sufficient to use global 'recent_time' here? I fear not... */
gettimeofday(&clock, NULL);
/* first, we update the cache if the time has changed */
diff --git a/lib/monotime.h b/lib/monotime.h
new file mode 100644
index 0000000000..0fd4940431
--- /dev/null
+++ b/lib/monotime.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2017 David Lamparter, for NetDEF, Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _FRR_MONOTIME_H
+#define _FRR_MONOTIME_H
+
+#include <stdint.h>
+#include <time.h>
+#include <sys/time.h>
+
+#ifndef TIMESPEC_TO_TIMEVAL
+/* should be in sys/time.h on BSD & Linux libcs */
+#define TIMESPEC_TO_TIMEVAL(tv, ts) do { \
+ (tv)->tv_sec = (ts)->tv_sec; \
+ (tv)->tv_usec = (ts)->tv_nsec / 1000; \
+ } while (0)
+#endif
+#ifndef TIMEVAL_TO_TIMESPEC
+/* should be in sys/time.h on BSD & Linux libcs */
+#define TIMEVAL_TO_TIMESPEC(tv, ts) do { \
+ (ts)->tv_sec = (tv)->tv_sec; \
+ (ts)->tv_nsec = (tv)->tv_usec * 1000; \
+ } while (0)
+#endif
+
+static inline time_t monotime(struct timeval *tvo)
+{
+ struct timespec ts;
+
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ if (tvo) {
+ TIMESPEC_TO_TIMEVAL(tvo, &ts);
+ }
+ return ts.tv_sec;
+}
+
+/* the following two return microseconds, not time_t!
+ *
+ * also, they're negative forms of each other, but having both makes the
+ * code more readable
+ */
+static inline int64_t monotime_since(const struct timeval *ref,
+ struct timeval *out)
+{
+ struct timeval tv;
+ monotime(&tv);
+ timersub(&tv, ref, &tv);
+ if (out)
+ *out = tv;
+ return (int64_t)tv.tv_sec * 1000000LL + tv.tv_usec;
+}
+
+static inline int64_t monotime_until(const struct timeval *ref,
+ struct timeval *out)
+{
+ struct timeval tv;
+ monotime(&tv);
+ timersub(ref, &tv, &tv);
+ if (out)
+ *out = tv;
+ return (int64_t)tv.tv_sec * 1000000LL + tv.tv_usec;
+}
+
+#endif /* _FRR_MONOTIME_H */
diff --git a/lib/thread.c b/lib/thread.c
index 64eaae45b9..de7066bb82 100644
--- a/lib/thread.c
+++ b/lib/thread.c
@@ -41,151 +41,16 @@ DEFINE_MTYPE_STATIC(LIB, THREAD_STATS, "Thread stats")
#include <mach/mach_time.h>
#endif
-/* Recent absolute time of day */
-struct timeval recent_time;
/* Relative time, since startup */
-static struct timeval relative_time;
-
static struct hash *cpu_record = NULL;
-/* Adjust so that tv_usec is in the range [0,TIMER_SECOND_MICRO).
- And change negative values to 0. */
-static struct timeval
-timeval_adjust (struct timeval a)
-{
- while (a.tv_usec >= TIMER_SECOND_MICRO)
- {
- a.tv_usec -= TIMER_SECOND_MICRO;
- a.tv_sec++;
- }
-
- while (a.tv_usec < 0)
- {
- a.tv_usec += TIMER_SECOND_MICRO;
- a.tv_sec--;
- }
-
- if (a.tv_sec < 0)
- /* Change negative timeouts to 0. */
- a.tv_sec = a.tv_usec = 0;
-
- return a;
-}
-
-static struct timeval
-timeval_subtract (struct timeval a, struct timeval b)
-{
- struct timeval ret;
-
- ret.tv_usec = a.tv_usec - b.tv_usec;
- ret.tv_sec = a.tv_sec - b.tv_sec;
-
- return timeval_adjust (ret);
-}
-
-static long
-timeval_cmp (struct timeval a, struct timeval b)
-{
- return (a.tv_sec == b.tv_sec
- ? a.tv_usec - b.tv_usec : a.tv_sec - b.tv_sec);
-}
-
-unsigned long
+static unsigned long
timeval_elapsed (struct timeval a, struct timeval b)
{
return (((a.tv_sec - b.tv_sec) * TIMER_SECOND_MICRO)
+ (a.tv_usec - b.tv_usec));
}
-/* gettimeofday wrapper, to keep recent_time updated */
-static int
-quagga_gettimeofday (struct timeval *tv)
-{
- int ret;
-
- assert (tv);
-
- if (!(ret = gettimeofday (&recent_time, NULL)))
- {
- /* avoid copy if user passed recent_time pointer.. */
- if (tv != &recent_time)
- *tv = recent_time;
- return 0;
- }
- return ret;
-}
-
-static int
-quagga_get_relative (struct timeval *tv)
-{
- int ret;
-
-#ifdef HAVE_CLOCK_MONOTONIC
- {
- struct timespec tp;
- if (!(ret = clock_gettime (CLOCK_MONOTONIC, &tp)))
- {
- relative_time.tv_sec = tp.tv_sec;
- relative_time.tv_usec = tp.tv_nsec / 1000;
- }
- }
-#elif defined(__APPLE__)
- {
- uint64_t ticks;
- uint64_t useconds;
- static mach_timebase_info_data_t timebase_info;
-
- ticks = mach_absolute_time();
- if (timebase_info.denom == 0)
- mach_timebase_info(&timebase_info);
-
- useconds = ticks * timebase_info.numer / timebase_info.denom / 1000;
- relative_time.tv_sec = useconds / 1000000;
- relative_time.tv_usec = useconds % 1000000;
-
- return 0;
- }
-#else /* !HAVE_CLOCK_MONOTONIC && !__APPLE__ */
-#error no monotonic clock on this system
-#endif /* HAVE_CLOCK_MONOTONIC */
-
- if (tv)
- *tv = relative_time;
-
- return ret;
-}
-
-/* Exported Quagga timestamp function.
- * Modelled on POSIX clock_gettime.
- */
-int
-quagga_gettime (enum quagga_clkid clkid, struct timeval *tv)
-{
- switch (clkid)
- {
- case QUAGGA_CLK_MONOTONIC:
- return quagga_get_relative (tv);
- default:
- errno = EINVAL;
- return -1;
- }
-}
-
-time_t
-quagga_monotime (void)
-{
- struct timeval tv;
- quagga_get_relative(&tv);
- return tv.tv_sec;
-}
-
-/* Public export of recent_relative_time by value */
-struct timeval
-recent_relative_time (void)
-{
- return relative_time;
-}
-
static unsigned int
cpu_record_hash_key (struct cpu_thread_history *a)
{
@@ -437,11 +302,9 @@ thread_timer_cmp(void *a, void *b)
struct thread *thread_a = a;
struct thread *thread_b = b;
- long cmp = timeval_cmp(thread_a->u.sands, thread_b->u.sands);
-
- if (cmp < 0)
+ if (timercmp (&thread_a->u.sands, &thread_b->u.sands, <))
return -1;
- if (cmp > 0)
+ if (timercmp (&thread_a->u.sands, &thread_b->u.sands, >))
return 1;
return 0;
}
@@ -671,12 +534,8 @@ thread_master_free (struct thread_master *m)
unsigned long
thread_timer_remain_second (struct thread *thread)
{
- quagga_get_relative (NULL);
-
- if (thread->u.sands.tv_sec - relative_time.tv_sec > 0)
- return thread->u.sands.tv_sec - relative_time.tv_sec;
- else
- return 0;
+ int64_t remain = monotime_until(&thread->u.sands, NULL) / 1000000LL;
+ return remain < 0 ? 0 : remain;
}
#define debugargdef const char *funcname, const char *schedfrom, int fromln
@@ -685,9 +544,9 @@ thread_timer_remain_second (struct thread *thread)
struct timeval
thread_timer_remain(struct thread *thread)
{
- quagga_get_relative(NULL);
-
- return timeval_subtract(thread->u.sands, relative_time);
+ struct timeval remain;
+ monotime_until(&thread->u.sands, &remain);
+ return remain;
}
/* Get new thread. */
@@ -887,7 +746,6 @@ funcname_thread_add_timer_timeval (struct thread_master *m,
{
struct thread *thread;
struct pqueue *queue;
- struct timeval alarm_time;
assert (m != NULL);
@@ -897,11 +755,8 @@ funcname_thread_add_timer_timeval (struct thread_master *m,
queue = ((type == THREAD_TIMER) ? m->timer : m->background);
thread = thread_get (m, type, func, arg, debugargpass);
- /* Do we need jitter here? */
- quagga_get_relative (NULL);
- alarm_time.tv_sec = relative_time.tv_sec + time_relative->tv_sec;
- alarm_time.tv_usec = relative_time.tv_usec + time_relative->tv_usec;
- thread->u.sands = timeval_adjust(alarm_time);
+ monotime(&thread->u.sands);
+ timeradd(&thread->u.sands, time_relative, &thread->u.sands);
pqueue_enqueue(thread, queue);
return thread;
@@ -1137,7 +992,7 @@ thread_timer_wait (struct pqueue *queue, struct timeval *timer_val)
if (queue->size)
{
struct thread *next_timer = queue->array[0];
- *timer_val = timeval_subtract (next_timer->u.sands, relative_time);
+ monotime_until(&next_timer->u.sands, timer_val);
return timer_val;
}
return NULL;
@@ -1265,7 +1120,7 @@ thread_timer_process (struct pqueue *queue, struct timeval *timenow)
while (queue->size)
{
thread = queue->array[0];
- if (timeval_cmp (*timenow, thread->u.sands) < 0)
+ if (timercmp (timenow, &thread->u.sands, <))
return ready;
pqueue_dequeue(queue);
thread->type = THREAD_READY;
@@ -1303,6 +1158,7 @@ thread_fetch (struct thread_master *m, struct thread *fetch)
thread_fd_set readfd;
thread_fd_set writefd;
thread_fd_set exceptfd;
+ struct timeval now;
struct timeval timer_val = { .tv_sec = 0, .tv_usec = 0 };
struct timeval timer_val_bg;
struct timeval *timer_wait = &timer_val;
@@ -1339,15 +1195,20 @@ thread_fetch (struct thread_master *m, struct thread *fetch)
/* Calculate select wait timer if nothing else to do */
if (m->ready.count == 0)
{
- quagga_get_relative (NULL);
timer_wait = thread_timer_wait (m->timer, &timer_val);
timer_wait_bg = thread_timer_wait (m->background, &timer_val_bg);
if (timer_wait_bg &&
- (!timer_wait || (timeval_cmp (*timer_wait, *timer_wait_bg) > 0)))
+ (!timer_wait || (timercmp (timer_wait, timer_wait_bg, >))))
timer_wait = timer_wait_bg;
}
+ if (timer_wait && timer_wait->tv_sec < 0)
+ {
+ timerclear(&timer_val);
+ timer_wait = &timer_val;
+ }
+
num = fd_select (m, FD_SETSIZE, &readfd, &writefd, &exceptfd, timer_wait);
/* Signals should get quick treatment */
@@ -1362,8 +1223,8 @@ thread_fetch (struct thread_master *m, struct thread *fetch)
/* Check foreground timers. Historically, they have had higher
priority than I/O threads, so let's push them onto the ready
list in front of the I/O threads. */
- quagga_get_relative (NULL);
- thread_timer_process (m->timer, &relative_time);
+ monotime(&now);
+ thread_timer_process (m->timer, &now);
/* Got IO, process it */
if (num > 0)
@@ -1379,7 +1240,7 @@ thread_fetch (struct thread_master *m, struct thread *fetch)
#endif
/* Background timer/events, lowest priority */
- thread_timer_process (m->background, &relative_time);
+ thread_timer_process (m->background, &now);
if ((thread = thread_trim_head (&m->ready)) != NULL)
return thread_run (m, thread, fetch);
@@ -1408,9 +1269,7 @@ thread_consumed_time (RUSAGE_T *now, RUSAGE_T *start, unsigned long *cputime)
int
thread_should_yield (struct thread *thread)
{
- quagga_get_relative (NULL);
- return (timeval_elapsed(relative_time, thread->real) >
- thread->yield);
+ return monotime_since(&thread->real, NULL) > (int64_t)thread->yield;
}
void
@@ -1422,17 +1281,8 @@ thread_set_yield_time (struct thread *thread, unsigned long yield_time)
void
thread_getrusage (RUSAGE_T *r)
{
- quagga_get_relative (NULL);
+ monotime(&r->real);
getrusage(RUSAGE_SELF, &(r->cpu));
- r->real = relative_time;
-
-#ifdef HAVE_CLOCK_MONOTONIC
- /* quagga_get_relative() only updates recent_time if gettimeofday
- * based, not when using CLOCK_MONOTONIC. As we export recent_time
- * and guarantee to update it before threads are run...
- */
- quagga_gettimeofday(&recent_time);
-#endif /* HAVE_CLOCK_MONOTONIC */
}
struct thread *thread_current = NULL;
diff --git a/lib/thread.h b/lib/thread.h
index c22bb4828d..a0801e1ecd 100644
--- a/lib/thread.h
+++ b/lib/thread.h
@@ -23,6 +23,7 @@
#define _ZEBRA_THREAD_H
#include <zebra.h>
+#include "monotime.h"
struct rusage_t
{
@@ -239,7 +240,6 @@ extern void thread_call (struct thread *);
extern unsigned long thread_timer_remain_second (struct thread *);
extern struct timeval thread_timer_remain(struct thread*);
extern int thread_should_yield (struct thread *);
-extern unsigned long timeval_elapsed (struct timeval a, struct timeval b);
/* set yield time for thread */
extern void thread_set_yield_time (struct thread *, unsigned long);
@@ -247,13 +247,6 @@ extern void thread_set_yield_time (struct thread *, unsigned long);
extern void thread_getrusage (RUSAGE_T *);
extern void thread_cmd_init (void);
-/* replacements for the system gettimeofday(), clock_gettime() and
- * time() functions, providing support for non-decrementing clock on
- * all systems, and fully monotonic on /some/ systems.
- */
-extern int quagga_gettime (enum quagga_clkid, struct timeval *);
-extern time_t quagga_monotime (void);
-
/* Returns elapsed real (wall clock) time. */
extern unsigned long thread_consumed_time(RUSAGE_T *after, RUSAGE_T *before,
unsigned long *cpu_time_elapsed);
@@ -262,8 +255,6 @@ extern unsigned long thread_consumed_time(RUSAGE_T *after, RUSAGE_T *before,
be used instead of calling gettimeofday if a recent value is sufficient.
This is guaranteed to be refreshed before a thread is called. */
extern struct timeval recent_time;
-/* Similar to recent_time, but a monotonically increasing time value */
-extern struct timeval recent_relative_time (void);
/* only for use in logging functions! */
extern struct thread *thread_current;