Switch internal timebase to monotonic uint64_t
authorHenning Rogge <hrogge@googlemail.com>
Sat, 25 Feb 2012 23:39:22 +0000 (00:39 +0100)
committerHenning Rogge <hrogge@googlemail.com>
Sat, 25 Feb 2012 23:39:22 +0000 (00:39 +0100)
src/common/common_types.h
src/core/CMakeLists.txt
src/core/olsr_clock.c
src/core/olsr_clock.h
src/core/olsr_timer.c
src/core/olsr_timer.h
src/core/os_linux/os_system_linux.c
src/core/os_system.h

index 918fa2a..48f9461 100644 (file)
 typedef unsigned char uint8_t;
 typedef unsigned short uint16_t;
 typedef unsigned int uint32_t;
+typedef unsigned long long uint64_t;
 typedef signed char int8_t;
 typedef signed short int16_t;
 typedef signed int int32_t;
+typedef signed long long int64_t;
 
 /* Minimum of signed integral types.  */
 # define INT8_MIN   (-128)
index e94bd8d..a79ca90 100644 (file)
@@ -43,6 +43,9 @@ ENDIF(ANDROID)
 ADD_LIBRARY(static_core STATIC ${OONF_CORE_SRCS})
 ADD_LIBRARY(${OONF_LIBPREFIX}_core SHARED ${OONF_CORE_SRCS})
 
+TARGET_LINK_LIBRARIES(static_core rt)
+TARGET_LINK_LIBRARIES(${OONF_LIBPREFIX}_core rt)
+
 IF(WIN32)
     TARGET_LINK_LIBRARIES(static_core static_common)
     TARGET_LINK_LIBRARIES(${OONF_LIBPREFIX}_core ${OONF_LIBPREFIX}_common)
index dce6e8e..102099a 100644 (file)
 #include "olsr_clock.h"
 #include "olsr.h"
 
+static int olsr_get_timezone(void);
+
 /* Timer data */
-static uint32_t now_times;             /* relative time compared to startup (in milliseconds */
-static struct timeval first_tv;        /* timevalue during startup */
-static struct timeval last_tv;         /* timevalue used for last olsr_times() calculation */
+static uint64_t now_times;             /* relative time compared to startup (in milliseconds */
 
 /* remember if initialized or not */
 OLSR_SUBSYSTEM_STATE(_clock_state);
 
-static int olsr_get_timezone(void);
-
 /**
  * Initialize olsr clock system
  * @return -1 if an error happened, 0 otherwise
@@ -69,13 +67,6 @@ olsr_clock_init(void) {
   if (olsr_subsystem_is_initialized(&_clock_state))
     return 0;
 
-  /* Grab initial timestamp */
-  if (os_system_gettimeofday(&first_tv)) {
-    OLSR_WARN(LOG_TIMER, "OS clock is not working: %s (%d)\n", strerror(errno), errno);
-    return -1;
-  }
-  last_tv = first_tv;
-
   if (olsr_clock_update()) {
     return -1;
   }
@@ -99,36 +90,11 @@ olsr_clock_cleanup(void) {
 int
 olsr_clock_update(void)
 {
-  struct timeval tv;
-  uint32_t t;
 
-  if (os_system_gettimeofday(&tv) != 0) {
+  if (os_system_gettime64(&now_times)) {
     OLSR_WARN(LOG_TIMER, "OS clock is not working: %s (%d)\n", strerror(errno), errno);
     return -1;
   }
-
-  /* test if time jumped backward or more than 60 seconds forward */
-  if (tv.tv_sec < last_tv.tv_sec || (tv.tv_sec == last_tv.tv_sec && tv.tv_usec < last_tv.tv_usec)
-      || tv.tv_sec - last_tv.tv_sec > 60) {
-    OLSR_WARN(LOG_TIMER, "Time jump (%d.%06d to %d.%06d)\n",
-              (int32_t) (last_tv.tv_sec), (int32_t) (last_tv.tv_usec), (int32_t) (tv.tv_sec), (int32_t) (tv.tv_usec));
-
-    t = (last_tv.tv_sec - first_tv.tv_sec) * 1000 + (last_tv.tv_usec - first_tv.tv_usec) / 1000;
-    t++;                        /* advance time by one millisecond */
-
-    first_tv = tv;
-    first_tv.tv_sec -= (t / 1000);
-    first_tv.tv_usec -= ((t % 1000) * 1000);
-
-    if (first_tv.tv_usec < 0) {
-      first_tv.tv_sec--;
-      first_tv.tv_usec += 1000000;
-    }
-    last_tv = tv;
-    now_times =  t;
-  }
-  last_tv = tv;
-  now_times = (tv.tv_sec - first_tv.tv_sec) * 1000 + (tv.tv_usec - first_tv.tv_usec) / 1000;
   return 0;
 }
 
@@ -136,54 +102,11 @@ olsr_clock_update(void)
  * Calculates the current time in the internal OLSR representation
  * @return current time
  */
-uint32_t
+uint64_t
 olsr_clock_getNow(void) {
   return now_times;
 }
 
-/**
- * Returns the number of milliseconds until the timestamp will happen
- * @param absolute timestamp
- * @return milliseconds until event will happen, negative if it already
- *   happened.
- */
-int32_t
-olsr_clock_getRelative(uint32_t absolute)
-{
-  uint32_t diff;
-  if (absolute > now_times) {
-    diff = absolute - now_times;
-
-    /* overflow ? */
-    if (diff > (1u << 31)) {
-      return -(int32_t) (0xffffffff - diff);
-    }
-    return (int32_t) (diff);
-  }
-
-  diff = now_times - absolute;
-  /* overflow ? */
-  if (diff > (1u << 31)) {
-    return (int32_t) (0xffffffff - diff);
-  }
-  return -(int32_t) (diff);
-}
-
-/**
- * Checks if a timestamp has already happened
- * @param absolute timestamp
- * @return true if the event already happened, false otherwise
- */
-bool
-olsr_clock_isPast(uint32_t absolute)
-{
-  if (absolute > now_times) {
-    return absolute - now_times > (1u << 31);
-  }
-
-  return now_times - absolute <= (1u << 31);
-}
-
 /**
  * converts an unsigned integer value into a string representation
  * (divided by 1000)
index b3723f3..d04e804 100644 (file)
@@ -63,9 +63,7 @@ EXPORT int olsr_clock_init(void) __attribute__((warn_unused_result));
 EXPORT void olsr_clock_cleanup(void);
 EXPORT int olsr_clock_update(void) __attribute__((warn_unused_result));
 
-EXPORT int32_t olsr_clock_getRelative(uint32_t absolute);
-EXPORT bool olsr_clock_isPast(uint32_t s);
-EXPORT uint32_t olsr_clock_getNow(void);
+EXPORT uint64_t olsr_clock_getNow(void);
 
 EXPORT uint32_t olsr_clock_decode_olsrv1(const uint8_t);
 EXPORT uint8_t olsr_clock_encode_olsrv1(const uint32_t);
@@ -81,12 +79,35 @@ EXPORT const char *olsr_clock_getWallclockString(struct timeval_buf *);
  * @param s milliseconds until timestamp
  * @return absolute time when event will happen
  */
-static inline uint32_t
-olsr_clock_get_absolute(uint32_t relative)
+static INLINE uint64_t
+olsr_clock_get_absolute(uint64_t relative)
 {
   return olsr_clock_getNow() + relative;
 }
 
+/**
+ * Returns the number of milliseconds until the timestamp will happen
+ * @param absolute timestamp
+ * @return milliseconds until event will happen, negative if it already
+ *   happened.
+ */
+static INLINE int64_t
+olsr_clock_getRelative(uint64_t absolute)
+{
+  return (int64_t)absolute - (int64_t)olsr_clock_getNow();
+}
+
+/**
+ * Checks if a timestamp has already happened
+ * @param absolute timestamp
+ * @return true if the event already happened, false otherwise
+ */
+static INLINE bool
+olsr_clock_isPast(uint64_t absolute)
+{
+  return absolute < olsr_clock_getNow();
+}
+
 #endif
 
 /*
index 0fc4ba7..c4d594b 100644 (file)
@@ -54,7 +54,7 @@
 
 /* Hashed root of all timers */
 static struct list_entity _timer_wheel[TIMER_WHEEL_SLOTS];
-static uint32_t _timer_last_run;        /* remember the last timeslot walk */
+static uint64_t _timer_last_run;        /* remember the last timeslot walk */
 
 /* Memory cookie for the timer manager */
 struct list_entity timerinfo_list;
@@ -64,7 +64,7 @@ static struct olsr_memcookie_info *_timer_mem_cookie = NULL;
 OLSR_SUBSYSTEM_STATE(_timer_state);
 
 /* Prototypes */
-static uint32_t calc_jitter(unsigned int rel_time, uint8_t jitter_pct, unsigned int random_val);
+static uint64_t calc_jitter(uint64_t rel_time, uint8_t jitter_pct, unsigned int random_val);
 
 /**
  * Initialize timer scheduler subsystem
@@ -177,7 +177,7 @@ olsr_timer_remove(struct olsr_timer_info *info) {
  * @return a pointer to the created entry
  */
 struct olsr_timer_entry *
-olsr_timer_start(unsigned int rel_time,
+olsr_timer_start(uint64_t rel_time,
     uint8_t jitter_pct, void *context, struct olsr_timer_info *ti)
 {
   struct olsr_timer_entry *timer;
@@ -262,7 +262,7 @@ olsr_timer_stop(struct olsr_timer_entry *timer)
  * @param jitter_pct new jitter expressed in percent.
  */
 void
-olsr_timer_change(struct olsr_timer_entry *timer, unsigned int rel_time, uint8_t jitter_pct)
+olsr_timer_change(struct olsr_timer_entry *timer, uint64_t rel_time, uint8_t jitter_pct)
 {
 #if !defined(REMOVE_LOG_DEBUG)
   struct timeval_buf timebuf;
@@ -306,7 +306,7 @@ olsr_timer_change(struct olsr_timer_entry *timer, unsigned int rel_time, uint8_t
  */
 void
 olsr_timer_set(struct olsr_timer_entry **timer_ptr,
-               unsigned int rel_time,
+               uint64_t rel_time,
                uint8_t jitter_pct, void *context, struct olsr_timer_info *ti)
 {
   assert(ti);          /* we want timer cookies everywhere */
@@ -331,8 +331,8 @@ olsr_timer_set(struct olsr_timer_entry **timer_ptr,
 void
 olsr_timer_walk(void)
 {
-  unsigned int total_timers_walked = 0, total_timers_fired = 0;
-  unsigned int wheel_slot_walks = 0;
+  int total_timers_walked = 0, total_timers_fired = 0;
+  int wheel_slot_walks = 0;
 
   /*
    * Check the required wheel slots since the last time a timer walk was invoked,
@@ -374,7 +374,7 @@ olsr_timer_walk(void)
   struct timeval_buf timebuf;
 #endif
         OLSR_DEBUG(LOG_TIMER, "TIMER: fire %s timer %p, ctx %p, "
-                   "at clocktick %u (%s)\n",
+                   "at clocktick %" PRIu64 " (%s)\n",
                    timer->timer_info->name,
                    timer, timer->timer_cb_context, _timer_last_run,
                    olsr_clock_getWallclockString(&timebuf));
@@ -441,10 +441,10 @@ olsr_timer_walk(void)
  * @param random_val cached random variable to calculate jitter
  * @return the absolute time when timer will fire
  */
-static uint32_t
-calc_jitter(unsigned int rel_time, uint8_t jitter_pct, unsigned int random_val)
+static uint64_t
+calc_jitter(uint64_t rel_time, uint8_t jitter_pct, unsigned int random_val)
 {
-  unsigned int jitter_time;
+  uint64_t jitter_time;
 
   /*
    * No jitter or, jitter larger than 99% does not make sense.
@@ -460,7 +460,8 @@ calc_jitter(unsigned int rel_time, uint8_t jitter_pct, unsigned int random_val)
   jitter_time = (jitter_pct * rel_time) / 100;
   jitter_time = random_val / (1 + RAND_MAX / (jitter_time + 1));
 
-  OLSR_DEBUG(LOG_TIMER, "TIMER: jitter %u%% rel_time %ums to %ums\n", jitter_pct, rel_time, rel_time - jitter_time);
+  OLSR_DEBUG(LOG_TIMER, "TIMER: jitter %u%% rel_time %" PRIu64 "ms to %" PRIu64 "ms\n",
+      jitter_pct, rel_time, rel_time - jitter_time);
 
   return olsr_clock_get_absolute(rel_time - jitter_time);
 }
index 624a674..fdc1534 100644 (file)
@@ -92,10 +92,10 @@ struct olsr_timer_entry {
   struct olsr_timer_info *timer_info;
 
   /* when timer shall fire (absolute internal timerstamp) */
-  uint32_t timer_clock;
+  uint64_t timer_clock;
 
   /* timeperiod between two timer events for periodical timers */
-  uint32_t timer_period;
+  uint64_t timer_period;
 
   /* the jitter expressed in percent */
   uint8_t timer_jitter_pct;
@@ -124,11 +124,11 @@ EXPORT void olsr_timer_walk(void);
 EXPORT void olsr_timer_add(struct olsr_timer_info *ti);
 EXPORT void olsr_timer_remove(struct olsr_timer_info *);
 
-EXPORT void olsr_timer_set(struct olsr_timer_entry **, uint32_t, uint8_t,
+EXPORT void olsr_timer_set(struct olsr_timer_entry **, uint64_t, uint8_t,
     void *, struct olsr_timer_info *);
-EXPORT struct olsr_timer_entry *olsr_timer_start(uint32_t, uint8_t,
+EXPORT struct olsr_timer_entry *olsr_timer_start(uint64_t, uint8_t,
     void *, struct olsr_timer_info *);
-EXPORT void olsr_timer_change(struct olsr_timer_entry *, uint32_t, uint8_t);
+EXPORT void olsr_timer_change(struct olsr_timer_entry *, uint64_t, uint8_t);
 EXPORT void olsr_timer_stop(struct olsr_timer_entry *);
 
 #endif /* OLSR_TIMER_H_ */
index 1c7a15e..a4e7215 100644 (file)
@@ -50,6 +50,8 @@
 #include <sys/ioctl.h>
 #include <errno.h>
 #include <unistd.h>
+#include <sys/time.h>
+#include <time.h>
 
 #include "common/common_types.h"
 #include "common/string.h"
@@ -115,6 +117,9 @@ static struct olsr_timer_info _netlink_timer= {
 /* built in rtnetlink multicast receiver */
 static struct os_system_netlink _rtnetlink_receiver;
 
+/* type of clock source to be used */
+static int _clock_source = 0;
+
 OLSR_SUBSYSTEM_STATE(_os_system_state);
 
 /**
@@ -123,6 +128,8 @@ OLSR_SUBSYSTEM_STATE(_os_system_state);
  */
 int
 os_system_init(void) {
+  struct timespec ts;
+
   if (olsr_subsystem_is_initialized(&_os_system_state)) {
     return 0;
   }
@@ -143,6 +150,17 @@ os_system_init(void) {
 
   olsr_timer_add(&_netlink_timer);
 
+#ifdef CLOCK_MONOTONIC_RAW
+  if (clock_gettime(CLOCK_MONOTONIC_RAW, &ts) == 0) {
+    _clock_source = CLOCK_MONOTONIC_RAW;
+  }
+#endif
+#ifdef CLOCK_MONOTONIC
+  if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
+    _clock_source = CLOCK_MONOTONIC;
+  }
+#endif
+
   olsr_subsystem_init(&_os_system_state);
   return 0;
 }
@@ -160,6 +178,45 @@ os_system_cleanup(void) {
   close(_ioctl_fd);
 }
 
+/**
+ * Reads the current time as a monotonic timestamp
+ * @param pointer to timestamp
+ * @return 0 if valid timestamp was read, negative otherwise
+ */
+int
+os_system_gettime64(uint64_t *t64) {
+  static time_t offset = 0, last_sec = 0;
+  int error;
+
+  if (_clock_source) {
+    struct timespec ts;
+
+    if ((error = clock_gettime(_clock_source, &ts)) != 0) {
+      return error;
+    }
+
+    *t64 = 1000ull * ts.tv_sec + ts.tv_nsec / 1000000ull;
+    return 0;
+  }
+  else {
+    struct timeval tv;
+
+    if ((error = gettimeofday(&tv, NULL)) != 0) {
+      return error;
+    }
+
+    tv.tv_sec += offset;
+    if (tv.tv_sec < last_sec || tv.tv_sec > last_sec + 60) {
+      offset += last_sec - tv.tv_sec;
+      tv.tv_sec = last_sec;
+    }
+    last_sec = tv.tv_sec;
+
+    *t64 = 1000ull * tv.tv_sec + tv.tv_usec/ 1000ull;
+    return 0;
+  }
+}
+
 /**
  * Set interface up or down
  * @param dev pointer to name of interface
index 37d4037..0b1cf14 100644 (file)
@@ -89,6 +89,8 @@
 EXPORT int os_system_init(void);
 EXPORT void os_system_cleanup(void);
 
+EXPORT int os_system_gettime64(uint64_t *t64);
+
 EXPORT int os_system_set_interface_state(const char *dev, bool up);
 
 EXPORT void os_system_openlog(void);