summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Jakma <paul.jakma@sun.com>2006-08-27 06:44:02 +0000
committerPaul Jakma <paul.jakma@sun.com>2006-08-27 06:44:02 +0000
commitdb9c0df934e62835bc09604a7ae7932693b4254a (patch)
tree7e382d6012701e345492756f7716d4f62030e9f8
parentf0894cf8c323a25053e1f5e82be3ea5d88c2aacb (diff)
[lib] Bug #134: threads should be more robust against backward time jumps
2006-08-25 Paul Jakma <paul.jakma@sun.com> * thread.c: (general) Add support for monotonic clock, it may still jump forward by huge amounts, but should be immune to going backwards. Fixes bug #134. (quagga_gettimeofday_relative_adjust) helper, does what name says - adjusts gettimeofday based relative timer. (quagga_gettimeofday) helper to keep recent_time up to date. (quagga_get_relative) helper, update and getch the relative timer using gettimeofday(). POSIX CLOCK_MONOTONIC is also supported, but the code is not enabled yet nor tested. (quagga_real_stabilised) helper, retrieve absolute time but stabilised so as to never decrease. (quagga_gettime) Exported interface, analogous to POSIX clock_gettime() in interface, supporting several clocks. (quagga_time) Exported interface, analogous to traditional time(), will never decrease. (recent_relative_time) Convenience function to retrieve relative_time timeval, similar to existing recent_time absolute timeval, for when an approximately recent value will do. (remainder) Update to use above helpers. (thread_getrusage) Previously was a macro, but needs to be a function to twiddle with thread.c private stuff. * thread.c: Point the GETRUSAGE macro at previous function. Export quagga_gettime, quagga_time and recent_relative_time for general use.
-rw-r--r--lib/ChangeLog27
-rw-r--r--lib/thread.c179
-rw-r--r--lib/thread.h28
3 files changed, 210 insertions, 24 deletions
diff --git a/lib/ChangeLog b/lib/ChangeLog
index 7a744393..01f45ba5 100644
--- a/lib/ChangeLog
+++ b/lib/ChangeLog
@@ -1,3 +1,30 @@
+2006-08-25 Paul Jakma <paul.jakma@sun.com>
+
+ * thread.c: (general) Add support for monotonic clock, it may still
+ jump forward by huge amounts, but should be immune to going
+ backwards. Fixes bug #134.
+ (quagga_gettimeofday_relative_adjust) helper, does what name
+ says - adjusts gettimeofday based relative timer.
+ (quagga_gettimeofday) helper to keep recent_time up to date.
+ (quagga_get_relative) helper, update and getch the relative
+ timer using gettimeofday(). POSIX CLOCK_MONOTONIC is also
+ supported, but the code is not enabled yet nor tested.
+ (quagga_real_stabilised) helper, retrieve absolute time but
+ stabilised so as to never decrease.
+ (quagga_gettime) Exported interface, analogous to POSIX
+ clock_gettime() in interface, supporting several clocks.
+ (quagga_time) Exported interface, analogous to traditional
+ time(), will never decrease.
+ (recent_relative_time) Convenience function to retrieve
+ relative_time timeval, similar to existing recent_time absolute
+ timeval, for when an approximately recent value will do.
+ (remainder) Update to use above helpers.
+ (thread_getrusage) Previously was a macro, but needs to be
+ a function to twiddle with thread.c private stuff.
+ * thread.c: Point the GETRUSAGE macro at previous function.
+ Export quagga_gettime, quagga_time and recent_relative_time for
+ general use.
+
2006-07-25 Paul Jakma <paul.jakma@sun.com>
* thread.h: (struct thread) Add a cache pointer to the struct
diff --git a/lib/thread.c b/lib/thread.c
index 8b6a7e2f..095dff4e 100644
--- a/lib/thread.c
+++ b/lib/thread.c
@@ -30,7 +30,15 @@
#include "command.h"
#include "sigevent.h"
+/* Recent absolute time of day */
struct timeval recent_time;
+static struct timeval last_recent_time;
+/* Relative time, since startup */
+static struct timeval relative_time;
+static struct timeval relative_time_base;
+/* init flag */
+static unsigned short timers_inited;
+
static struct hash *cpu_record = NULL;
/* Struct timeval's tv_usec one second value. */
@@ -85,6 +93,129 @@ timeval_elapsed (struct timeval a, struct timeval b)
+ (a.tv_usec - b.tv_usec));
}
+#ifndef HAVE_CLOCK_MONOTONIC
+static void
+quagga_gettimeofday_relative_adjust (void)
+{
+ struct timeval diff;
+ if (timeval_cmp (recent_time, last_recent_time) < 0)
+ {
+ relative_time.tv_sec++;
+ relative_time.tv_usec = 0;
+ }
+ else
+ {
+ diff = timeval_subtract (recent_time, last_recent_time);
+ relative_time.tv_sec += diff.tv_sec;
+ relative_time.tv_usec += diff.tv_usec;
+ relative_time = timeval_adjust (relative_time);
+ }
+ last_recent_time = recent_time;
+}
+#endif /* !HAVE_CLOCK_MONOTONIC */
+
+/* gettimeofday wrapper, to keep recent_time updated */
+static int
+quagga_gettimeofday (struct timeval *tv)
+{
+ int ret;
+
+ assert (tv);
+
+ if (!(ret = gettimeofday (&recent_time, NULL)))
+ {
+ /* init... */
+ if (!timers_inited)
+ {
+ relative_time_base = last_recent_time = recent_time;
+ timers_inited = 1;
+ }
+ /* 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;
+ }
+ }
+#else /* !HAVE_CLOCK_MONOTONIC */
+ if (!(ret = quagga_gettimeofday (&recent_time)))
+ quagga_gettimeofday_relative_adjust();
+#endif /* HAVE_CLOCK_MONOTONIC */
+
+ if (tv)
+ *tv = relative_time;
+
+ return ret;
+}
+
+/* Get absolute time stamp, but in terms of the internal timer
+ * Could be wrong, but at least won't go back.
+ */
+static void
+quagga_real_stabilised (struct timeval *tv)
+{
+ *tv = relative_time_base;
+ tv->tv_sec += relative_time.tv_sec;
+ tv->tv_usec += relative_time.tv_usec;
+ *tv = timeval_adjust (*tv);
+}
+
+/* Exported Quagga timestamp function.
+ * Modelled on POSIX clock_gettime.
+ */
+int
+quagga_gettime (enum quagga_clkid clkid, struct timeval *tv)
+{
+ switch (clkid)
+ {
+ case QUAGGA_CLK_REALTIME:
+ return quagga_gettimeofday (tv);
+ case QUAGGA_CLK_MONOTONIC:
+ return quagga_get_relative (tv);
+ case QUAGGA_CLK_REALTIME_STABILISED:
+ quagga_real_stabilised (tv);
+ return 0;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+}
+
+/* time_t value in terms of stabilised absolute time.
+ * replacement for POSIX time()
+ */
+time_t
+quagga_time (time_t *t)
+{
+ struct timeval tv;
+ quagga_real_stabilised (&tv);
+ if (t)
+ *t = tv.tv_sec;
+ 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)
{
@@ -396,10 +527,10 @@ thread_trim_head (struct thread_list *list)
unsigned long
thread_timer_remain_second (struct thread *thread)
{
- gettimeofday (&recent_time, NULL);
-
- if (thread->u.sands.tv_sec - recent_time.tv_sec > 0)
- return thread->u.sands.tv_sec - recent_time.tv_sec;
+ 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;
}
@@ -515,8 +646,8 @@ funcname_thread_add_timer_timeval (struct thread_master *m,
const char* funcname)
{
struct thread *thread;
- struct timeval alarm_time;
struct thread_list *list;
+ struct timeval alarm_time;
struct thread *tt;
assert (m != NULL);
@@ -528,9 +659,9 @@ funcname_thread_add_timer_timeval (struct thread_master *m,
thread = thread_get (m, type, func, arg, funcname);
/* Do we need jitter here? */
- gettimeofday (&recent_time, NULL);
- alarm_time.tv_sec = recent_time.tv_sec + time_relative->tv_sec;
- alarm_time.tv_usec = recent_time.tv_usec + time_relative->tv_usec;
+ quagga_gettimeofday (&recent_time);
+ 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);
/* Sort by timeval. */
@@ -693,7 +824,7 @@ thread_timer_wait (struct thread_list *tlist, struct timeval *timer_val)
{
if (!thread_empty (tlist))
{
- *timer_val = timeval_subtract (tlist->head->u.sands, recent_time);
+ *timer_val = timeval_subtract (tlist->head->u.sands, relative_time);
return timer_val;
}
return NULL;
@@ -790,7 +921,7 @@ thread_fetch (struct thread_master *m, struct thread *fetch)
exceptfd = m->exceptfd;
/* Calculate select wait timer if nothing else to do */
- gettimeofday (&recent_time, NULL);
+ quagga_get_relative (NULL);
timer_wait = thread_timer_wait (&m->timer, &timer_val);
timer_wait_bg = thread_timer_wait (&m->background, &timer_val_bg);
@@ -812,8 +943,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. */
- gettimeofday (&recent_time, NULL);
- thread_timer_process (&m->timer, &recent_time);
+ quagga_get_relative (NULL);
+ thread_timer_process (&m->timer, &relative_time);
/* Got IO, process it */
if (num > 0)
@@ -834,7 +965,7 @@ thread_fetch (struct thread_master *m, struct thread *fetch)
#endif
/* Background timer/events, lowest priority */
- thread_timer_process (&m->background, &recent_time);
+ thread_timer_process (&m->background, &relative_time);
if ((thread = thread_trim_head (&m->ready)) != NULL)
return thread_run (m, thread, fetch);
@@ -866,11 +997,29 @@ thread_consumed_time (RUSAGE_T *now, RUSAGE_T *start, unsigned long *cputime)
int
thread_should_yield (struct thread *thread)
{
- gettimeofday(&recent_time, NULL);
- return (timeval_elapsed(recent_time, thread->ru.real) >
+ quagga_get_relative (NULL);
+ return (timeval_elapsed(relative_time, thread->ru.real) >
THREAD_YIELD_TIME_SLOT);
}
+void
+thread_getrusage (RUSAGE_T *r)
+{
+ quagga_get_relative (NULL);
+#ifdef HAVE_RUSAGE
+ getrusage(RUSAGE_SELF, &(r->cpu));
+#endif
+ 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 */
+}
+
/* We check thread consumed time. If the system has getrusage, we'll
use that to get in-depth stats on the performance of the thread in addition
to wall clock time stats from gettimeofday. */
diff --git a/lib/thread.h b/lib/thread.h
index 0670a890..1c324d86 100644
--- a/lib/thread.h
+++ b/lib/thread.h
@@ -31,14 +31,7 @@ struct rusage_t
};
#define RUSAGE_T struct rusage_t
-#ifdef HAVE_RUSAGE
-#define GETRUSAGE(X) \
- getrusage(RUSAGE_SELF, &((X)->cpu)); \
- gettimeofday(&recent_time, NULL); (X)->real = recent_time
-#else
-#define GETRUSAGE(X) \
- gettimeofday(&recent_time, NULL); (X)->real = recent_time
-#endif /* HAVE_RUSAGE */
+#define GETRUSAGE(X) thread_getrusage(X)
/* Linked list of thread. */
struct thread_list
@@ -99,6 +92,13 @@ struct cpu_thread_history
unsigned char types;
};
+/* Clocks supported by Quagga */
+enum quagga_clkid {
+ QUAGGA_CLK_REALTIME = 0, /* ala gettimeofday() */
+ QUAGGA_CLK_MONOTONIC, /* monotonic, against an indeterminate base */
+ QUAGGA_CLK_REALTIME_STABILISED, /* like realtime, but non-decrementing */
+};
+
/* Thread types. */
#define THREAD_READ 0
#define THREAD_WRITE 1
@@ -192,8 +192,17 @@ extern void thread_call (struct thread *);
extern unsigned long thread_timer_remain_second (struct thread *);
extern int thread_should_yield (struct thread *);
+/* Internal libzebra exports */
+extern void thread_getrusage (RUSAGE_T *);
extern struct cmd_element show_thread_cpu_cmd;
+/* 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_time (time_t *);
+
/* Returns elapsed real (wall clock) time. */
extern unsigned long thread_consumed_time(RUSAGE_T *after, RUSAGE_T *before,
unsigned long *cpu_time_elapsed);
@@ -202,5 +211,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);
#endif /* _ZEBRA_THREAD_H */