[Olsr-dev] [PATCH v1 1/2] scheduler: mark timers for removal and only remove them in a cleanup walk

Ferry Huberts (spam-protected)
Mon Feb 29 15:23:59 CET 2016


From: Ferry Huberts <(spam-protected)>

Fixes crashes in networks with many nodes.

*** olsr.org - pre-0.9.1-git_dd7c5a0-hash_b9729ef932ee0c718b5da79dcf6a5fce ***
 Build date: 2016-02-24 21:02:23 on jenkins
 http://www.olsr.org

/usr/sbin/olsrd               (olsr_segv_handler)          src/main.c:323
/lib/i386-linux-gnu/libc.so.6 (+0x2de78)                   [0xb760ce78]
/usr/sbin/olsrd               (list_remove)                src/common/list.c:105
/usr/sbin/olsrd               (olsr_stop_timer)            src/scheduler.c:874
/usr/sbin/olsrd               (olsr_del_nbr2_list)         src/neighbor_table.c:85
/usr/sbin/olsrd               (olsr_delete_neighbor_table) src/neighbor_table.c:211
/usr/sbin/olsrd               (olsr_delete_link_entry)     src/link_set.c:375
/usr/sbin/olsrd               (olsr_expire_link_entry)     src/link_set.c:495
/usr/sbin/olsrd               (walk_timers)                src/scheduler.c:650
/usr/sbin/olsrd               (olsr_scheduler)             src/scheduler.c:506
/usr/sbin/olsrd               (main)                       src/main.c:705

olsrd crashed, stack trace follows
/usr/sbin/olsrd               (olsr_segv_handler)          src/main.c:323
/lib/i386-linux-gnu/libc.so.6 (+0x2de78)                   [0xb764ce78]
/usr/sbin/olsrd               (list_remove)                src/common/list.c:105
/usr/sbin/olsrd               (olsr_stop_timer)            src/scheduler.c:874
/usr/sbin/olsrd               (olsr_update_gateway_entry)  src/gateway.c:1208
/usr/sbin/olsrd               (olsr_input_hna)             src/hna_set.c:446
/usr/sbin/olsrd               (parse_packet)               src/parser.c:393
/usr/sbin/olsrd               (olsr_input)                 src/parser.c:496
/usr/sbin/olsrd               (poll_sockets)               src/scheduler.c:341
/usr/sbin/olsrd               (olsr_scheduler)             src/scheduler.c:499
/usr/sbin/olsrd               (main)                       src/main.c:705

Signed-off-by: Ferry Huberts <(spam-protected)>
---
 src/scheduler.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 src/scheduler.h |  1 +
 2 files changed, 94 insertions(+), 2 deletions(-)

diff --git a/src/scheduler.c b/src/scheduler.c
index cf8968a..062c96e 100644
--- a/src/scheduler.c
+++ b/src/scheduler.c
@@ -47,6 +47,7 @@
 #include "net_os.h"
 #include "mpr_selector_set.h"
 #include "olsr_random.h"
+#include "common/avl.h"
 
 #include <sys/times.h>
 
@@ -74,8 +75,44 @@ static struct list_node socket_head = { &socket_head, &socket_head };
 
 /* Prototypes */
 static void walk_timers(uint32_t *);
+static void walk_timers_cleanup(void);
 static void poll_sockets(void);
 static uint32_t calc_jitter(unsigned int rel_time, uint8_t jitter_pct, unsigned int random_val);
+static void olsr_cleanup_timer(struct timer_entry *timer);
+
+struct avl_tree timer_cleanup_tree;
+
+struct timer_cleanup_entry {
+  struct avl_node avl;
+  struct timer_entry * timer;
+};
+
+/* static inline struct timer_cleanup_entry * node2timercleanup(struct avl_node *ptr) */
+AVLNODE2STRUCT(node2timercleanup, struct timer_cleanup_entry, avl);
+
+/**
+ * Loop over all timer cleanup entries and put the iterated entry in timer
+ */
+#define OLSR_FOR_ALL_TIMERS_CLEANUP(timer) \
+{ \
+  struct avl_node *timer_avl_node, *timer_avl_node_next; \
+  for (timer_avl_node = avl_walk_first(&timer_cleanup_tree); \
+  timer_avl_node; timer_avl_node = timer_avl_node_next) { \
+	  timer_avl_node_next = avl_walk_next(timer_avl_node); \
+    timer = node2timercleanup(timer_avl_node);
+#define OLSR_FOR_ALL_TIMER_CLEANUP_END(timer) }}
+
+static int avl_comp_timer(const void *entry1, const void *entry2) {
+  if (entry1 < entry2) {
+    return -1;
+  }
+
+  if (entry1 > entry2) {
+    return -1;
+  }
+
+  return 0;
+}
 
 /*
  * A wrapper around times(2). Note, that this function has some
@@ -504,6 +541,7 @@ void olsr_scheduler(void)
 
     /* Process timers */
     walk_timers(&timer_last_run);
+    walk_timers_cleanup();
 
     if (state != RUNNING) {
       break;
@@ -530,6 +568,7 @@ void olsr_scheduler(void)
     /* Read incoming data and handle it immediiately */
     handle_fds(next_interval);
   }
+  walk_timers_cleanup();
 
   state = ENDED;
 }
@@ -583,6 +622,8 @@ olsr_init_timers(void)
   last_tv = first_tv;
   now_times = olsr_times();
 
+  avl_init(&timer_cleanup_tree, avl_comp_timer);
+
   for (idx = 0; idx < TIMER_WHEEL_SLOTS; idx++) {
     list_head_init(&timer_wheel[idx]);
   }
@@ -638,6 +679,10 @@ walk_timers(uint32_t * last_run)
       list_add_after(&tmp_head_node, timer_node);
       timers_walked++;
 
+      if (timer->timer_flags & OLSR_TIMER_REMOVED) {
+        continue;
+      }
+
       /* Ready to fire ? */
       if (TIMED_OUT(timer->timer_clock)) {
 
@@ -694,6 +739,16 @@ walk_timers(uint32_t * last_run)
   *last_run = now_times;
 }
 
+static void walk_timers_cleanup(void) {
+  struct timer_cleanup_entry * timer;
+
+  OLSR_FOR_ALL_TIMERS_CLEANUP(timer) {
+    olsr_cleanup_timer(timer->timer);
+    avl_delete(&timer_cleanup_tree, &timer->avl);
+    free(timer);
+  } OLSR_FOR_ALL_TIMER_CLEANUP_END(slot)
+}
+
 /**
  * Stop and delete all timers.
  */
@@ -711,6 +766,7 @@ olsr_flush_timers(void)
       olsr_stop_timer(list2timer(timer_head_node->next));
     }
   }
+  walk_timers_cleanup();
 }
 
 /**
@@ -858,7 +914,8 @@ void
 olsr_stop_timer(struct timer_entry *timer)
 {
   /* It's okay to get a NULL here */
-  if (!timer) {
+  if (!timer //
+      || (timer->timer_flags & OLSR_TIMER_REMOVED)) {
     return;
   }
 
@@ -868,11 +925,45 @@ olsr_stop_timer(struct timer_entry *timer)
              timer->timer_cookie->ci_name, timer, timer->timer_cb_context);
 
 
+  timer->timer_flags &= ~OLSR_TIMER_RUNNING;
+  timer->timer_flags |= OLSR_TIMER_REMOVED;
+
+  {
+    struct timer_cleanup_entry * node = olsr_malloc(sizeof(struct timer_cleanup_entry), "timer cleanup entry");
+    node->avl.key = timer;
+    node->timer = timer;
+    if (avl_insert(&timer_cleanup_tree, &node->avl, AVL_DUP_NO) == -1) {
+      /* duplicate */
+      free(node);
+    }
+  }
+}
+
+/**
+ * Clean up a timer.
+ *
+ * @param timer the timer_entry that shall be cleaned up
+ */
+static void
+olsr_cleanup_timer(struct timer_entry *timer)
+{
+  /* It's okay to get a NULL here */
+  if (!timer //
+      || !(timer->timer_flags & OLSR_TIMER_REMOVED)) {
+    return;
+  }
+
+  assert(timer->timer_cookie);     /* we want timer cookies everywhere */
+
+  OLSR_PRINTF(7, "TIMER: cleanup %s timer %p, ctx %p\n",
+             timer->timer_cookie->ci_name, timer, timer->timer_cb_context);
+
+
   /*
    * Carve out of the existing wheel_slot and free.
    */
   list_remove(&timer->timer_list);
-  timer->timer_flags &= ~OLSR_TIMER_RUNNING;
+  timer->timer_flags &= ~OLSR_TIMER_REMOVED;
   olsr_cookie_usage_decr(timer->timer_cookie->ci_id);
 
   olsr_cookie_free(timer_mem_cookie, timer);
diff --git a/src/scheduler.h b/src/scheduler.h
index a18198b..6afc791 100644
--- a/src/scheduler.h
+++ b/src/scheduler.h
@@ -90,6 +90,7 @@ LISTNODE2STRUCT(list2timer, struct timer_entry, timer_list);
 
 /* Timer flags */
 #define OLSR_TIMER_RUNNING  ( 1 << 0)   /* this timer is running */
+#define OLSR_TIMER_REMOVED  ( 1 << 1)   /* this timer is tagged for removal */
 
 /* Timers */
 void olsr_init_timers(void);
-- 
2.5.0




More information about the Olsr-dev mailing list