Several small fixes distributed through the framework
authorHenning Rogge <henning.rogge@fkie.fraunhofer.de>
Fri, 2 Mar 2012 13:40:23 +0000 (14:40 +0100)
committerHenning Rogge <henning.rogge@fkie.fraunhofer.de>
Fri, 2 Mar 2012 13:40:23 +0000 (14:40 +0100)
13 files changed:
lib/remotecontrol/src/remotecontrol.c
src/config/cfg_cmd.c
src/config/cfg_db.c
src/config/cfg_db.h
src/config/cfg_schema.c
src/core/olsr_cfg.c
src/core/olsr_clock.c
src/core/olsr_clock.h
src/core/olsr_socket.c
src/core/olsr_timer.c
src/core/olsr_timer.h
src/core/os_linux/os_routing_linux.c
src/core/os_linux/os_system_linux.c

index 56e8241..84f3a3a 100644 (file)
@@ -523,8 +523,8 @@ _cb_handle_config(struct olsr_telnet_data *data) {
   }
 
   if ((next = str_hasnextword(data->parameter, "commit"))) {
-    if (!cfg_schema_validate(olsr_cfg_get_rawdb(),
-        false, true, data->out)) {
+    if (cfg_schema_validate(olsr_cfg_get_rawdb(),
+        false, true, data->out) == 0) {
       olsr_cfg_trigger_commit();
     }
   }
index da454da..62c56cf 100644 (file)
@@ -211,7 +211,7 @@ cfg_cmd_handle_get(struct cfg_instance *instance, struct cfg_db *db,
   struct cfg_named_section *named, *named_it;
   struct cfg_entry *entry, *entry_it;
   struct _parsed_argument pa;
-  char *ptr;
+  char *arg_copy, *tmp;
   int result;
 
   if (arg == NULL || *arg == 0) {
@@ -223,15 +223,15 @@ cfg_cmd_handle_get(struct cfg_instance *instance, struct cfg_db *db,
     return 0;
   }
 
-  ptr = strdup(arg);
-  if (!ptr) {
+  arg_copy = strdup(arg);
+  if (!arg_copy) {
     return -1;
   }
 
   /* prepare for cleanup */
   result = -1;
 
-  if (_do_parse_arg(instance, ptr, &pa, log)) {
+  if (_do_parse_arg(instance, arg_copy, &pa, log)) {
     goto handle_get_cleanup;
   }
 
@@ -248,8 +248,8 @@ cfg_cmd_handle_get(struct cfg_instance *instance, struct cfg_db *db,
     }
 
     cfg_append_printable_line(log, "Key '%s' has value:", arg);
-    FOR_ALL_STRINGS(&entry->val, ptr) {
-      cfg_append_printable_line(log, "%s", ptr);
+    FOR_ALL_STRINGS(&entry->val, tmp) {
+      cfg_append_printable_line(log, "%s", tmp);
     }
     result = 0;
     goto handle_get_cleanup;
@@ -286,7 +286,7 @@ cfg_cmd_handle_get(struct cfg_instance *instance, struct cfg_db *db,
   result = 0;
 
 handle_get_cleanup:
-  free(ptr);
+  free(arg_copy);
   return result;
 }
 
index 8097ad0..38698c4 100644 (file)
@@ -132,8 +132,8 @@ _cfg_db_append(struct cfg_db *dst, struct cfg_db *src,
         }
 
         FOR_ALL_STRINGS(&entry->val, ptr) {
-          if (cfg_db_set_entry(
-              dst, section->type, named->name, entry->name, ptr, true) == NULL) {
+          if (cfg_db_set_entry_ext(
+              dst, section->type, named->name, entry->name, ptr, true, false) == NULL) {
             return -1;
           }
         }
@@ -260,12 +260,14 @@ cfg_db_remove_namedsection(struct cfg_db *db, const char *section_type,
  * @param value entry value
  * @param append true if the value should be appended to a list,
  *   false if it should overwrite all old values
+ * @param front true if the value should be put in front of existing
+ *   values, false if it should be put at the end
  * @return pointer to cfg_entry, NULL if an error happened
  */
 struct cfg_entry *
-cfg_db_set_entry(struct cfg_db *db, const char *section_type,
+cfg_db_set_entry_ext(struct cfg_db *db, const char *section_type,
     const char *section_name, const char *entry_name, const char *value,
-    bool prepend) {
+    bool append, bool front) {
   struct cfg_entry *entry;
   struct cfg_named_section *named;
   bool new_section = false, new_entry = NULL;
@@ -286,12 +288,19 @@ cfg_db_set_entry(struct cfg_db *db, const char *section_type,
     new_entry = true;
   }
 
-  if (!prepend) {
+  if (!append) {
     strarray_free(&entry->val);
   }
   /* prepend new entry */
-  if (strarray_prepend(&entry->val, value)) {
-    goto set_entry_error;
+  if (front) {
+    if (strarray_prepend(&entry->val, value)) {
+      goto set_entry_error;
+    }
+  }
+  else {
+    if (strarray_append(&entry->val, value)) {
+      goto set_entry_error;
+    }
   }
 
   return entry;
index 396d385..71e9686 100644 (file)
@@ -128,8 +128,9 @@ EXPORT struct cfg_named_section *cfg_db_find_namedsection(
 EXPORT int cfg_db_remove_namedsection(struct cfg_db *db, const char *section_type,
     const char *section_name);
 
-EXPORT struct cfg_entry *cfg_db_set_entry(struct cfg_db *db, const char *section_type,
-    const char *section_name, const char *entry_name, const char *value, bool append);
+EXPORT struct cfg_entry *cfg_db_set_entry_ext(struct cfg_db *db, const char *section_type,
+    const char *section_name, const char *entry_name, const char *value,
+    bool append, bool front);
 
 EXPORT struct cfg_entry *cfg_db_find_entry(struct cfg_db *db,
     const char *section_type, const char *section_name, const char *entry_name);
@@ -342,6 +343,24 @@ cfg_db_add_unnamedsection(
   return _cfg_db_add_section(db, section_type, NULL, &dummy);
 }
 
+/**
+ * Sets an entry to a configuration database
+ * @param db pointer to configuration database
+ * @param section_type type of section
+ * @param section_name name of section, NULL if an unnamed one
+ * @param entry_name entry name
+ * @param value entry value
+ * @param append true if the value should be put in front of a list,
+ *   false if it should overwrite all old values
+ * @return pointer to cfg_entry, NULL if an error happened
+ */
+static INLINE struct cfg_entry *
+cfg_db_set_entry(struct cfg_db *db, const char *section_type,
+    const char *section_name, const char *entry_name, const char *value,
+    bool append) {
+  return cfg_db_set_entry_ext(db, section_type, section_name, entry_name,
+      value, append, true);
+}
 
 /**
  * Adds an entry to a configuration database
index be7b04b..aa9925e 100644 (file)
@@ -643,8 +643,14 @@ cfg_schema_help_choice(
 void
 cfg_schema_help_int(
     const struct cfg_schema_entry *entry, struct autobuf *out) {
-  cfg_append_printable_line(out, "    Parameter must be an integer between %d and %d",
-      entry->validate_params.p_i1, entry->validate_params.p_i2);
+  if (entry->validate_params.p_i1 > INT32_MIN
+      && entry->validate_params.p_i2 < INT32_MAX) {
+    cfg_append_printable_line(out, "    Parameter must be an integer between %d and %d",
+        entry->validate_params.p_i1, entry->validate_params.p_i2);
+  }
+  else {
+    cfg_append_printable_line(out, "    Parameter must be an integer");
+  }
 }
 
 /**
@@ -899,8 +905,11 @@ _validate_cfg_entry(struct cfg_db *db, struct cfg_section_type *section,
     const char *section_name, bool cleanup, struct autobuf *out) {
   struct cfg_schema_entry *schema_entry, *s_entry_it;
   struct cfg_schema_entry_key key;
-  bool warning = false;
-  char *ptr1 = NULL;
+  bool warning, do_remove;
+  char *ptr1;
+
+  warning = false;
+  ptr1 = NULL;
 
   key.type = section->type;
   key.entry = entry->name;
@@ -920,31 +929,31 @@ _validate_cfg_entry(struct cfg_db *db, struct cfg_section_type *section,
 
     /* now validate syntax */
     ptr1 = entry->val.value;
+
+    do_remove = false;
     while (ptr1 < entry->val.value + entry->val.length) {
-      if (schema_entry->cb_validate(schema_entry, section_name, ptr1, out)) {
+      if (!do_remove && schema_entry->cb_validate(schema_entry, section_name, ptr1, out) != 0) {
         /* warning is generated by the validate callback itself */
         warning = true;
       }
 
-    if (warning && cleanup) {
-      /* illegal entry found, remove it */
-      strarray_remove_ext(&entry->val, ptr1, false);
-    }
-    else {
-      ptr1 += strlen(ptr1) + 1;
-    }
+      if ((warning || do_remove) && cleanup) {
+        /* illegal entry found, remove it */
+        strarray_remove_ext(&entry->val, ptr1, false);
+      }
+      else {
+        ptr1 += strlen(ptr1) + 1;
+      }
 
-    if (!schema_entry->list) {
-      /* ignore the rest */
-      break;
+      if (!schema_entry->list) {
+        do_remove = true;
+      }
     }
-  }
 
-  if (strarray_is_empty(&entry->val)
-      || (!schema_entry->list && warning && cleanup)) {
-    /* remove entry */
-    cfg_db_remove_entry(db, section->type, named->name, entry->name);
-  }
+    if (strarray_is_empty(&entry->val)) {
+      /* remove entry */
+      cfg_db_remove_entry(db, section->type, named->name, entry->name);
+    }
   }
   return warning;
 }
index b0e4af6..304d314 100644 (file)
@@ -48,6 +48,7 @@
 
 #include "olsr_logging.h"
 #include "olsr_plugins.h"
+#include "olsr_socket.h"
 #include "olsr_cfg.h"
 #include "olsr.h"
 
@@ -154,6 +155,7 @@ olsr_cfg_cleanup(void) {
  */
 void
 olsr_cfg_trigger_reload(void) {
+  OLSR_DEBUG(LOG_CONFIG, "Config reload triggered");
   _trigger_reload = true;
 }
 
@@ -170,7 +172,8 @@ olsr_cfg_is_reload_set(void) {
  */
 void
 olsr_cfg_trigger_commit(void) {
-  _trigger_reload = true;
+  OLSR_DEBUG(LOG_CONFIG, "Config commit triggered");
+  _trigger_commit = true;
 }
 
 /**
@@ -178,7 +181,7 @@ olsr_cfg_trigger_commit(void) {
  */
 bool
 olsr_cfg_is_commit_set(void) {
-  return _trigger_reload;
+  return _trigger_commit;
 }
 
 /**
@@ -232,7 +235,7 @@ olsr_cfg_loadplugins(void) {
 int
 olsr_cfg_apply(void) {
   struct olsr_plugin *plugin, *plugin_it;
-  struct cfg_db *new_db, *old_db;
+  struct cfg_db *old_db;
   struct autobuf log;
   int result;
 
@@ -259,17 +262,18 @@ olsr_cfg_apply(void) {
     goto apply_failed;
   }
 
+  /* backup old db */
+  old_db = _olsr_work_db;
+
   /* create new configuration database with correct values */
-  new_db = cfg_db_duplicate(_olsr_raw_db);
-  if (new_db == NULL) {
+  _olsr_work_db = cfg_db_duplicate(_olsr_raw_db);
+  if (_olsr_work_db == NULL) {
     OLSR_WARN_OOM(LOG_CONFIG);
+    _olsr_work_db = old_db;
+    old_db = NULL;
     goto apply_failed;
   }
 
-  /* switch databases */
-  old_db = _olsr_work_db;
-  _olsr_work_db = new_db;
-
   /* bind schema */
   cfg_db_link_schema(_olsr_work_db, &_olsr_schema);
 
@@ -284,7 +288,7 @@ olsr_cfg_apply(void) {
   }
 
   /* remove everything not valid */
-  cfg_schema_validate(new_db, true, false, NULL);
+  cfg_schema_validate(_olsr_work_db, true, false, NULL);
 
   if (olsr_cfg_update_globalcfg(false)) {
     /* this should not happen at all */
@@ -306,6 +310,11 @@ olsr_cfg_apply(void) {
   _trigger_reload = false;
   _trigger_commit = false;
 
+  /* now get a new working copy of the committed settings */
+  cfg_db_remove(_olsr_raw_db);
+  _olsr_raw_db = cfg_db_duplicate(_olsr_work_db);
+  cfg_db_link_schema(_olsr_raw_db, &_olsr_schema);
+
 apply_failed:
   /* look for loaded but not enabled plugins and unload them */
   OLSR_FOR_ALL_PLUGIN_ENTRIES(plugin, plugin_it) {
index 90da7b9..197515a 100644 (file)
@@ -45,6 +45,9 @@
 #include <stdio.h>
 #include <time.h>
 
+#include "config/cfg_schema.h"
+#include "config/cfg.h"
+
 #include "os_clock.h"
 #include "olsr_logging.h"
 #include "olsr_clock.h"
@@ -128,7 +131,7 @@ olsr_clock_toClockString(struct timeval_buf *buf, uint64_t clk)
   uint64_t msec = clk % MSEC_PER_SEC;
   uint64_t sec = clk / MSEC_PER_SEC;
 
-  snprintf(buf->buf, sizeof(buf),
+  snprintf(buf->buf, sizeof(*buf),
       "%"PRIu64":%02"PRIu64":%02"PRIu64".%03"PRIu64"",
       sec / 3600, (sec % 3600) / 60, (sec % 60), msec);
 
@@ -146,44 +149,54 @@ olsr_clock_toClockString(struct timeval_buf *buf, uint64_t clk)
 const char *
 olsr_clock_toIntervalString(struct timeval_buf *buf, uint64_t clk)
 {
-  snprintf(buf->buf, sizeof(buf),
+  snprintf(buf->buf, sizeof(*buf),
       "%"PRIu64".%03"PRIu64"", clk / MSEC_PER_SEC, clk % MSEC_PER_SEC);
   return buf->buf;
 }
 
-uint64_t
-olsr_clock_fromIntervalString(const char *string) {
+int
+olsr_clock_fromIntervalString(uint64_t *result, const char *string) {
   bool period;
   uint64_t t;
   int post_period;
   char c;
 
+  if (*string == 0) {
+    return -1;
+  }
+
   /* initialize variables */
   post_period = 0;
   period = false;
   t = 0;
 
   /* parse string */
-  while ((c = *string++) != 0 && post_period < 3) {
+  while ((c = *string) != 0 && post_period < 3) {
     if (c == '.') {
       if (period) {
         /* error, no two '.' allowed */
-        return 0;
+        return -1;
       }
       period = true;
-      continue;
-    }
-
-    if (c < '0' || c > '9') {
-      /* error, no-digit character found */
-      return 0;
     }
+    else {
+      if (c < '0' || c > '9') {
+        /* error, no-digit character found */
+        return -1;
+      }
 
-    t = t * 10ull + (c - '0');
+      t = t * 10ull + (c - '0');
 
-    if (period) {
-      post_period++;
+      if (period) {
+        post_period++;
+      }
     }
+    string++;
+  }
+
+  if (*string) {
+    /* string too long */
+    return -1;
   }
 
   /* shift number to factor 1000 */
@@ -191,5 +204,83 @@ olsr_clock_fromIntervalString(const char *string) {
     t *= 10;
   }
 
-  return t;
+  *result = t;
+  return 0;
+}
+
+/**
+ * Checks a value of a CLOCK field for validity.
+ * See CFG_VALIDATE_TIME() macro in olr_clock.h
+ * @param entry pointer to schema entry
+ * @param section_name name of section type and name
+ * @param value value of schema entry
+ * @param out pointer to autobuffer for validator output
+ * @return 0 if validation found no problems, -1 otherwise
+ */
+int
+olsr_clock_validate(const struct cfg_schema_entry *entry,
+    const char *section_name, const char *value, struct autobuf *out) {
+  uint64_t num;
+
+  if (olsr_clock_fromIntervalString(&num, value)) {
+    cfg_append_printable_line(out, "Value '%s' for entry '%s'"
+        " in section %s is not a valid fractional integer"
+        " (positive or zero, maximum of 3 fractional digits)",
+        value, entry->key.entry, section_name);
+    return -1;
+  }
+
+  if (entry->validate_params.p_i1 != -1
+      && num < (unsigned)(entry->validate_params.p_i1)) {
+    cfg_append_printable_line(out, "Value '%s' for entry '%s'"
+        " in section %s must be larger than %d)",
+        value, entry->key.entry, section_name,
+        entry->validate_params.p_i1);
+    return -1;
+  }
+  if (entry->validate_params.p_i2 != -1
+      && num > (unsigned)(entry->validate_params.p_i1)) {
+    cfg_append_printable_line(out, "Value '%s' for entry '%s'"
+        " in section %s must be smaller than %d",
+        value, entry->key.entry, section_name,
+        entry->validate_params.p_i2);
+    return -1;
+  }
+  return 0;
+}
+
+/**
+ * Binary converter for time intervals.
+ * See CFG_MAP_TIME() macro in olr_clock.h
+ * @param s_entry pointer to configuration entry schema.
+ * @param value pointer to value of configuration entry.
+ * @param reference pointer to binary output buffer.
+ * @return 0 if conversion succeeded, -1 otherwise.
+ */
+int
+olsr_clock_tobin(
+    const struct cfg_schema_entry *s_entry __attribute__((unused)),
+    const struct const_strarray *value, void *reference) {
+  return olsr_clock_fromIntervalString(reference, strarray_get_first_c(value));
+}
+
+/**
+ * Help generator for time validator.
+ * See CFG_VALIDATE_TIME() and CFG_VALIDATE_TIME_MINMAX() macro in olr_clock.h
+ * @param entry pointer to schema entry
+ * @param out pointer to autobuffer for validator output
+ */
+void
+olsr_clock_help(
+    const struct cfg_schema_entry *entry, struct autobuf *out) {
+  cfg_append_printable_line(out,
+      "    Parameter must be an timestamp with a maximum of 3 fractional digits");
+  if (entry->validate_params.p_i1 != -1) {
+    cfg_append_printable_line(out,
+        "    Minimal valid time is %d.0", entry->validate_params.p_i1);
+  }
+  if (entry->validate_params.p_i2 != -1) {
+    cfg_append_printable_line(out,
+        "    Maximum valid time is %d.0", entry->validate_params.p_i2);
+  }
 }
index db49e7c..0947c55 100644 (file)
@@ -43,6 +43,7 @@
 #define _OLSR_CLOCK
 
 #include "common/common_types.h"
+#include "config/cfg_schema.h"
 
 /* Some defs for juggling with timers */
 #define MSEC_PER_SEC 1000
 #define NSEC_PER_USEC 1000
 #define USEC_PER_MSEC 1000
 
-struct millitxt_buf {
-  char buf[20];
-};
+/* definitions for config parser usage */
+#define CFG_VALIDATE_CLOCK(p_name, p_def, p_help, args...)                      _CFG_VALIDATE(p_name, p_def, p_help, .cb_validate = olsr_clock_validate, .cb_valhelp = olsr_clock_help, .validate_params = {.p_i1 = -1, .p_i2 = -1}, ##args )
+#define CFG_VALIDATE_CLOCK_MIN(p_name, p_def, p_help, p_min, args...)           _CFG_VALIDATE(p_name, p_def, p_help, .cb_validate = olsr_clock_validate, .cb_valhelp = olsr_clock_help, .validate_params = {.p_i1 = p_min, .p_i2 = -1},##args )
+#define CFG_VALIDATE_CLOCK_MAX(p_name, p_def, p_help, p_min, args...)           _CFG_VALIDATE(p_name, p_def, p_help, .cb_validate = olsr_clock_validate, .cb_valhelp = olsr_clock_help, .validate_params = {.p_i1 = -1, .p_i2 = p_max},##args )
+#define CFG_VALIDATE_CLOCK_MINMAX(p_name, p_def, p_help, p_min, p_max, args...) _CFG_VALIDATE(p_name, p_def, p_help, .cb_validate = olsr_clock_validate, .cb_valhelp = olsr_clock_help, .validate_params = {.p_i1 = p_min, .p_i2 = p_max},##args )
+
+#define CFG_MAP_CLOCK(p_reference, p_field, p_name, p_def, p_help, args...)                      CFG_VALIDATE_CLOCK(p_name, p_def, p_help, .cb_to_binary = olsr_clock_tobin, .bin_offset = offsetof(struct p_reference, p_field), ##args)
+#define CFG_MAP_CLOCK_MIN(p_reference, p_field, p_name, p_def, p_help, p_min, args...)           CFG_VALIDATE_CLOCK(p_name, p_def, p_help, p_min, .cb_to_binary = olsr_clock_tobin, .bin_offset = offsetof(struct p_reference, p_field), ##args)
+#define CFG_MAP_CLOCK_MAX(p_reference, p_field, p_name, p_def, p_help, p_max, args...)           CFG_VALIDATE_CLOCK(p_name, p_def, p_help, p_max, .cb_to_binary = olsr_clock_tobin, .bin_offset = offsetof(struct p_reference, p_field), ##args)
+#define CFG_MAP_CLOCK_MINMAX(p_reference, p_field, p_name, p_def, p_help, p_min, p_max, args...) CFG_VALIDATE_CLOCK(p_name, p_def, p_help, p_min, p_max, .cb_to_binary = olsr_clock_tobin, .bin_offset = offsetof(struct p_reference, p_field), ##args)
 
 /* buffer for displaying absolute timestamps */
 struct timeval_buf {
@@ -67,7 +75,14 @@ EXPORT uint64_t olsr_clock_getNow(void);
 
 EXPORT const char *olsr_clock_toClockString(struct timeval_buf *, uint64_t);
 EXPORT const char *olsr_clock_toIntervalString(struct timeval_buf *, uint64_t);
-EXPORT uint64_t olsr_clock_fromIntervalString(const char *string);
+EXPORT int olsr_clock_fromIntervalString(uint64_t *result, const char *string);
+
+EXPORT int olsr_clock_validate(const struct cfg_schema_entry *entry,
+    const char *section_name, const char *value, struct autobuf *out);
+EXPORT int olsr_clock_tobin(const struct cfg_schema_entry *s_entry,
+    const struct const_strarray *value, void *reference);
+EXPORT void  olsr_clock_help(
+    const struct cfg_schema_entry *entry, struct autobuf *out);
 
 /**
  * Returns a timestamp s seconds in the future
index 285885b..6594eb8 100644 (file)
@@ -47,6 +47,7 @@
 
 #include "common/avl.h"
 #include "common/avl_comp.h"
+#include "olsr_cfg.h"
 #include "olsr_clock.h"
 #include "olsr_logging.h"
 #include "os_net.h"
@@ -138,7 +139,7 @@ olsr_socket_handle(uint64_t stop_time)
     stop_time = ~0ull;
   }
 
-  while (olsr_is_running()) {
+  while (true) {
     fd_set ibits, obits;
     int hfd = 0;
 
@@ -155,6 +156,10 @@ olsr_socket_handle(uint64_t stop_time)
       olsr_timer_walk();
     }
 
+    if (!olsr_is_running() || olsr_cfg_is_commit_set() || olsr_cfg_is_reload_set()) {
+      return 0;
+    }
+
     /* no event left for now, prepare for select () */
     fd_read = false;
     fd_write = false;
@@ -200,7 +205,7 @@ olsr_socket_handle(uint64_t stop_time)
     }
 
     do {
-      if (!olsr_is_running()) {
+      if (!olsr_is_running() || olsr_cfg_is_commit_set() || olsr_cfg_is_reload_set()) {
         return 0;
       }
       n = os_select(hfd,
index f32e1e4..910fc2f 100644 (file)
 /* power of 2 for the number of elements in each bucket */
 #define BUCKET_COUNT_POW2     9ull
 
-#define BUCKET_COUNT          (1ull << BUCKET_COUNT_POW2)
-
 /* power of 2 for the number of milliseconds each bucket represents */
 #define BUCKET_TIMESLICE_POW2 7ull
 
-#define BUCKET_TIMESLICE      (1ull << BUCKET_TIMESLICE_POW2)
-
 /* maximum number of milliseconds a timer can use */
-#define TIMER_MAX_RELTIME     (1ull << (BUCKET_COUNT_POW2 * BUCKET_DEPTH + BUCKET_COUNT_POW2))
+const uint64_t BUCKET_COUNT = (1ull << BUCKET_COUNT_POW2);
+const uint64_t BUCKET_TIMESLICE = (1ull << BUCKET_TIMESLICE_POW2);
+const uint64_t TIMER_MAX_RELTIME = (1ull << (BUCKET_COUNT_POW2 * BUCKET_DEPTH + BUCKET_TIMESLICE_POW2));
+const uint64_t BUCKET_TIMESLICE_MASK = ~((1ull << BUCKET_TIMESLICE_POW2) - 1);
 
 /* root of all timers */
-static struct list_entity _buckets[BUCKET_COUNT][BUCKET_DEPTH];
+static struct list_entity _buckets[1ull << BUCKET_COUNT_POW2][BUCKET_DEPTH];
 static int _bucket_ptr[BUCKET_DEPTH];
 
 /* time when the next timer will fire */
@@ -78,6 +77,9 @@ static uint64_t _next_fire_event;
 /* number of timer events still in queue */
 static uint32_t _total_timer_events;
 
+/* true if scheduler is active */
+static bool _scheduling_now;
+
 /* Memory cookie for the timer manager */
 struct list_entity timerinfo_list;
 
@@ -86,7 +88,7 @@ OLSR_SUBSYSTEM_STATE(_timer_state);
 
 /* Prototypes */
 static void _calc_clock(struct olsr_timer_entry *timer, uint64_t rel_time);
-static void _insert_into_bucket(struct olsr_timer_entry *);
+static int _insert_into_bucket(struct olsr_timer_entry *);
 static void _calculate_next_event(void);
 
 /**
@@ -123,6 +125,7 @@ olsr_timer_init(void)
   /* at the moment we have no timer */
   _next_fire_event = ~0ull;
   _total_timer_events = 0;
+  _scheduling_now = false;
 
   list_init_head(&timerinfo_list);
 }
@@ -201,9 +204,10 @@ void
 olsr_timer_start(struct olsr_timer_entry *timer, uint64_t rel_time)
 {
 #if !defined(REMOVE_LOG_DEBUG)
-  struct timeval_buf timebuf;
+  struct timeval_buf timebuf1;
 #endif
   uint64_t stored_time;
+  int new_slot;
 
   assert(timer->info);
   assert(timer->jitter_pct <= 100);
@@ -231,24 +235,42 @@ olsr_timer_start(struct olsr_timer_entry *timer, uint64_t rel_time)
   _calc_clock(timer, rel_time);
 
   /* Singleshot or periodical timer ? */
-  timer->period = timer->info->periodic ? rel_time : 0;
+  timer->_period = timer->info->periodic ? rel_time : 0;
 
   /*
    * Now insert in the respective _timer_wheel slot.
    */
-  _insert_into_bucket(timer);
+  new_slot = _insert_into_bucket(timer);
 
   /* and update internal time data */
   _total_timer_events++;
-  if (timer->_clock < _next_fire_event) {
+
+  OLSR_DEBUG(LOG_TIMER, "TIMER: start timer '%s' firing in %s\n",
+             timer->info->name, olsr_clock_toClockString(&timebuf1, rel_time));
+
+  /* fix 'next event' pointers if necessary */
+  if (_scheduling_now) {
+    /* will be fixed at the end of the timer scheduling loop */
+    return;
+  }
+
+  if (timer->_clock <= _next_fire_event) {
+    /* we have a new 'earliest' event */
     _next_fire_event = timer->_clock;
+
+    if (new_slot != -1) {
+      /* earliest event in depth 0 buckets ! */
+      _bucket_ptr[0] = new_slot;
+    }
+    else {
+      /* just jump to the last bucket of the current loop to speed up scheduler */
+      _bucket_ptr[0] = BUCKET_COUNT - 1;
+    }
   }
-  else if (stored_time == _next_fire_event) {
+  else if (list_is_empty(&_buckets[_bucket_ptr[0]][0])) {
+    /* event got later and now the 'earliest bucket' is empty */
     _calculate_next_event();
   }
-
-  OLSR_DEBUG(LOG_TIMER, "TIMER: start timer %s firing in %s\n",
-             timer->info->name, olsr_clock_toClockString(&timebuf, rel_time));
 }
 
 /**
@@ -277,7 +299,8 @@ olsr_timer_stop(struct olsr_timer_entry *timer)
 
   /* and update internal time data */
   _total_timer_events--;
-  if (_next_fire_event == timer->_clock) {
+  if (!_scheduling_now && list_is_empty(&_buckets[_bucket_ptr[0]][0])) {
+    /* we are outside the event loop and now the 'earliest bucket' is empty */
     _calculate_next_event();
   }
 }
@@ -287,7 +310,7 @@ olsr_timer_stop(struct olsr_timer_entry *timer)
  * Depending on the passed in parameters a new timer is started,
  * or an existing timer is started or an existing timer is
  * terminated.
- * @param timer_ptr pointer to timer_entry pointer
+ * @param timer_ptr timer_entry pointer
  * @param rel_time time until the new timer should fire, 0 to stop timer
  */
 void
@@ -298,7 +321,7 @@ olsr_timer_set(struct olsr_timer_entry *timer, uint64_t rel_time)
     olsr_timer_stop(timer);
   }
   else {
-    /* No timer running, kick it. */
+    /* Start or restart the timer */
     olsr_timer_start(timer, rel_time);
   }
 }
@@ -315,13 +338,13 @@ olsr_timer_walk(void)
 
   int i;
 
+  _scheduling_now = true;
+
   while (_next_fire_event <= olsr_clock_getNow()) {
     i = _bucket_ptr[0];
     list_for_each_element_safe(&_buckets[i][0], timer, _node, t_it) {
-      OLSR_DEBUG(LOG_TIMER, "TIMER: fire %s timer %p, ctx %p, "
-                  "at clocktick %" PRIu64 "\n",
-                  timer->info->name,
-                  timer, timer->cb_context, _next_fire_event);
+      OLSR_DEBUG(LOG_TIMER, "TIMER: fire '%s' at clocktick %" PRIu64 "\n",
+                  timer->info->name, _next_fire_event);
 
       /*
        * The timer->info pointer is invalidated by olsr_timer_stop()
@@ -333,7 +356,7 @@ olsr_timer_walk(void)
       /* update statistics */
       info->changes++;
 
-      if (timer->period == 0) {
+      if (timer->_period == 0) {
         /* stop now, the data structure might not be available anymore later */
         olsr_timer_stop(timer);
       }
@@ -351,13 +374,15 @@ olsr_timer_walk(void)
          * rehash the random number and restart
          */
         timer->_random = random();
-        olsr_timer_start(timer, timer->period);
+        olsr_timer_start(timer, timer->_period);
       }
     }
 
     /* advance our 'next event' marker */
     _calculate_next_event();
   }
+
+  _scheduling_now = false;
 }
 
 /**
@@ -371,8 +396,9 @@ olsr_timer_getNextEvent(void) {
 /**
  * Puts a timer into the corresponding bucket
  * @param timer pointer to initialized timer struct
+ * @return index of bucket if in group 0, otherwise -1
  */
-static void
+static int
 _insert_into_bucket(struct olsr_timer_entry *timer) {
   uint64_t slot;
   int64_t relative;
@@ -386,12 +412,14 @@ _insert_into_bucket(struct olsr_timer_entry *timer) {
     if (relative < (int64_t)BUCKET_COUNT) {
       slot &= (BUCKET_COUNT - 1);
       list_add_tail(&_buckets[slot][group], &timer->_node);
-      return;
+
+      return group == 0 ? (int)slot : -1;
     }
   }
 
   OLSR_WARN(LOG_TIMER, "Error, timer event too far in the future: %" PRIu64,
       olsr_clock_getRelative(timer->_clock));
+  return -1;
 }
 
 
@@ -405,7 +433,7 @@ _insert_into_bucket(struct olsr_timer_entry *timer) {
 static void
 _calc_clock(struct olsr_timer_entry *timer, uint64_t rel_time)
 {
-  uint64_t jitter_time = 0;
+  uint64_t t = 0;
   unsigned random_jitter;
 
   if (timer->jitter_pct) {
@@ -413,12 +441,15 @@ _calc_clock(struct olsr_timer_entry *timer, uint64_t rel_time)
      * Play some tricks to avoid overflows with integer arithmetic.
      */
     random_jitter = timer->_random / (RAND_MAX / timer->jitter_pct);
-    jitter_time = (uint64_t)random_jitter * rel_time / 100;
+    t = (uint64_t)random_jitter * rel_time / 100;
 
     OLSR_DEBUG(LOG_TIMER, "TIMER: jitter %u%% rel_time %" PRIu64 "ms to %" PRIu64 "ms\n",
-        timer->jitter_pct, rel_time, rel_time - jitter_time);
+        timer->jitter_pct, rel_time, rel_time - t);
   }
-  timer->_clock = olsr_clock_get_absolute(rel_time - jitter_time);
+  t = olsr_clock_get_absolute(rel_time - t);
+
+  /* round to bucket border */
+  timer->_clock = (t + BUCKET_TIMESLICE/2) & BUCKET_TIMESLICE_MASK;
 }
 
 static void
@@ -485,5 +516,5 @@ _calculate_next_event(void) {
 
   /* get the timestamp when the first bucket will happen */
   timer = list_first_element(&_buckets[_bucket_ptr[0]][0], timer, _node);
-  _next_fire_event = timer->_clock & (~((uint64_t)BUCKET_TIMESLICE - 1));
+  _next_fire_event = timer->_clock;
 }
index 5809e69..edd093d 100644 (file)
@@ -96,15 +96,15 @@ struct olsr_timer_entry {
   /* backpointer to timer info */
   struct olsr_timer_info *info;
 
-  /* timeperiod between two timer events for periodical timers */
-  uint64_t period;
-
   /* the jitter expressed in percent */
   uint8_t jitter_pct;
 
   /* context pointer */
   void *cb_context;
 
+  /* timeperiod between two timer events for periodical timers */
+  uint64_t _period;
+
   /* cache random() result for performance reasons */
   unsigned int _random;
 
@@ -129,4 +129,13 @@ EXPORT void olsr_timer_stop(struct olsr_timer_entry *);
 
 EXPORT uint64_t olsr_timer_getNextEvent(void);
 
+/**
+ * @param timer pointer to timer
+ * @return true if the timer is running, false otherwise
+ */
+static INLINE bool
+olsr_timer_is_active(struct olsr_timer_entry *timer) {
+  return timer->_clock > 0ull;
+}
+
 #endif /* OLSR_TIMER_H_ */
index bc9366a..005229c 100644 (file)
@@ -85,7 +85,12 @@ static char _original_rp_filter;
 static char _original_icmp_redirect;
 
 /* netlink socket for route set/get commands */
-struct os_system_netlink _rtnetlink_socket;
+struct os_system_netlink _rtnetlink_socket = {
+  .cb_message = _cb_rtnetlink_message,
+  .cb_error = _cb_rtnetlink_error,
+  .cb_done = _cb_rtnetlink_done,
+  .cb_timeout = _cb_rtnetlink_timeout,
+};
 struct list_entity _rtnetlink_feedback;
 
 OLSR_SUBSYSTEM_STATE(_os_routing_state);
@@ -115,11 +120,6 @@ os_routing_init(void) {
     return -1;
   }
 
-  _rtnetlink_socket.cb_message = _cb_rtnetlink_message;
-  _rtnetlink_socket.cb_error = _cb_rtnetlink_error;
-  _rtnetlink_socket.cb_done = _cb_rtnetlink_done;
-  _rtnetlink_socket.cb_timeout = _cb_rtnetlink_timeout;
-
   if (_os_linux_writeToProc(PROC_ALL_REDIRECT, &_original_icmp_redirect, '0')) {
     OLSR_WARN(LOG_OS_SYSTEM, "WARNING! Could not disable ICMP redirects! "
         "You should manually ensure that ICMP redirects are disabled!");
index c520815..d59bb24 100644 (file)
@@ -115,7 +115,9 @@ static struct olsr_timer_info _netlink_timer= {
 };
 
 /* built in rtnetlink multicast receiver */
-static struct os_system_netlink _rtnetlink_receiver;
+static struct os_system_netlink _rtnetlink_receiver = {
+  .cb_message = _handle_rtnetlink,
+};
 
 OLSR_SUBSYSTEM_STATE(_os_system_state);
 
@@ -141,7 +143,6 @@ os_system_init(void) {
     close(_ioctl_fd);
     return -1;
   }
-  _rtnetlink_receiver.cb_message = _handle_rtnetlink;
 
   olsr_timer_add(&_netlink_timer);
 
@@ -207,7 +208,7 @@ os_system_set_interface_state(const char *dev, bool up) {
 
 /**
  * Open a new bidirectional netlink socket
- * @param nl pointer to uninitialized netlink socket handler
+ * @param nl pointer to initialized netlink socket handler
  * @param protocol protocol id (NETLINK_ROUTING for example)
  * @param multicast multicast groups this socket should listen to
  * @return -1 if an error happened, 0 otherwise
@@ -216,8 +217,6 @@ int
 os_system_netlink_add(struct os_system_netlink *nl, int protocol, uint32_t multicast) {
   struct sockaddr_nl addr;
 
-  memset(nl, 0, sizeof(*nl));
-
   nl->socket.fd = socket(PF_NETLINK, SOCK_RAW, protocol);
   if (nl->socket.fd < 0) {
     OLSR_WARN(LOG_OS_SYSTEM, "Cannot open sync rtnetlink socket: %s (%d)",