diff options
author | Joakim Tjernlund <Joakim.Tjernlund@transmode.se> | 2008-09-02 11:10:51 +0200 |
---|---|---|
committer | David Lamparter <equinox@diac24.net> | 2010-02-03 05:05:43 +0100 |
commit | 78ad0d902cd5dd765f1f67a8b9ab740c60d50158 (patch) | |
tree | b40ee3a8bcff3e50da0fcba242200c853e4ca77a /lib | |
parent | d6ad8a772a1bf03f2df90ca63e8b23e64a9f5f7e (diff) | |
download | quagga-78ad0d902cd5dd765f1f67a8b9ab740c60d50158.tar.bz2 quagga-78ad0d902cd5dd765f1f67a8b9ab740c60d50158.tar.xz |
lib: Use times(2) to calculate relative time.
times(2) is monotonic, use it to calculate relative_time
and scale the value using sysconf(_SC_CLK_TCK);
Diffstat (limited to 'lib')
-rw-r--r-- | lib/thread.c | 120 |
1 files changed, 84 insertions, 36 deletions
diff --git a/lib/thread.c b/lib/thread.c index c6ee8964..70f8defa 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -20,8 +20,9 @@ */ /* #define DEBUG */ - +#include <errno.h> #include <zebra.h> +#include <sys/times.h> #include "thread.h" #include "memory.h" @@ -32,7 +33,6 @@ /* Recent absolute time of day */ static 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; @@ -94,54 +94,98 @@ timeval_elapsed (struct timeval a, struct timeval b) } #ifndef HAVE_CLOCK_MONOTONIC +static unsigned long recent_clock_mark; /* Holds value of last call to times(2) */ +static unsigned long last_clock_mark; +static unsigned long clocks_per_sec, msec_scale, usec_scale; + +static unsigned long quagga_times(void) +{ +#if defined(GNU_LINUX) + unsigned long ret; + + errno = 0; + ret = times(NULL); /* Linux can handle NULL */ + /* Workaround broken syscall impl. + * A bugfix exists for the kernel, hopefully + * it will make it into 2.6.28 + */ + if (errno) + ret = (unsigned long) (-errno); + return ret; +#else + struct tms dummy; /* Only return value is used */ + + return times(&dummy); +#endif +} + 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; + unsigned long diff; + + diff = recent_clock_mark - last_clock_mark; + if (!diff) + return; + /* save mark for next calculation */ + last_clock_mark = recent_clock_mark; + + relative_time.tv_sec += diff / clocks_per_sec; /* convert to seconds */ + relative_time.tv_usec += (diff % clocks_per_sec) * usec_scale; /* convert to useconds */ + relative_time = timeval_adjust (relative_time); } #endif /* !HAVE_CLOCK_MONOTONIC */ +static int init_quagga_timers(void) +{ + int ret; + + ret = gettimeofday (&recent_time, NULL); + relative_time_base = recent_time; +#if !defined(HAVE_CLOCK_MONOTONIC) + clocks_per_sec = sysconf(_SC_CLK_TCK); + assert(clocks_per_sec != 0); + + /* Precondition: 1000 % clocks_per_sec == 0 */ + assert(1000 % clocks_per_sec == 0); + msec_scale = 1000 / clocks_per_sec; + + /* Precondition: TIMER_SECOND_MICRO % clocks_per_sec == 0 */ + assert(TIMER_SECOND_MICRO % clocks_per_sec == 0); + usec_scale = TIMER_SECOND_MICRO / clocks_per_sec; + recent_clock_mark = quagga_times(); + last_clock_mark = recent_clock_mark; +#endif + if (ret) + return ret; + timers_inited = 1; + return 0; +} + /* 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; + + /* init... */ + if (!timers_inited) + ret = init_quagga_timers(); + else + ret = gettimeofday (&recent_time, NULL); + if (ret) + return ret; + + /* avoid copy if user passed recent_time pointer.. */ + if (tv != &recent_time) + *tv = recent_time; + return 0; } static int quagga_get_relative (struct timeval *tv) { - int ret; + int ret = 0; #ifdef HAVE_CLOCK_MONOTONIC { @@ -153,8 +197,12 @@ quagga_get_relative (struct timeval *tv) } } #else /* !HAVE_CLOCK_MONOTONIC */ - if (!(ret = quagga_gettimeofday (&recent_time))) - quagga_gettimeofday_relative_adjust(); + /* init... */ + if (!timers_inited) + ret = init_quagga_timers(); + + recent_clock_mark = quagga_times(); + quagga_gettimeofday_relative_adjust(); #endif /* HAVE_CLOCK_MONOTONIC */ if (tv) |