[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 20:57:20 CET 2016



On 29/02/16 15:23, Ferry Huberts wrote:
> 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;

This should be 'return 1;' ofcourse
Corrected locally.

> +  }
> +
> +  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);
>

-- 
Ferry Huberts



More information about the Olsr-dev mailing list