Fix race condition if timer frees() its memory structure in callback
authorHenning Rogge <henning.rogge@fkie.fraunhofer.de>
Thu, 1 Mar 2012 08:11:35 +0000 (09:11 +0100)
committerHenning Rogge <henning.rogge@fkie.fraunhofer.de>
Thu, 1 Mar 2012 08:11:35 +0000 (09:11 +0100)
src/core/olsr_timer.c
src/core/olsr_timer.h

index 156eee5..273566f 100644 (file)
@@ -166,7 +166,7 @@ olsr_timer_cleanup(void)
  */
 void
 olsr_timer_add(struct olsr_timer_info *ti) {
-  list_add_tail(&timerinfo_list, &ti->node);
+  list_add_tail(&timerinfo_list, &ti->_node);
 }
 
 /**
@@ -190,7 +190,7 @@ olsr_timer_remove(struct olsr_timer_info *info) {
     }
   }
 
-  list_remove(&info->node);
+  list_remove(&info->_node);
 }
 
 /**
@@ -272,6 +272,10 @@ olsr_timer_stop(struct olsr_timer_entry *timer)
   timer->info->usage--;
   timer->info->changes++;
 
+  if (timer->info->_timer_in_callback == timer) {
+    timer->info->_timer_stopped = true;
+  }
+
   /* and update internal time data */
   _total_timer_events--;
   if (_next_fire_event == timer->_clock) {
@@ -308,6 +312,8 @@ void
 olsr_timer_walk(void)
 {
   struct olsr_timer_entry *timer, *t_it;
+  struct olsr_timer_info *info;
+
   int i;
 
   while (_next_fire_event <= olsr_clock_getNow()) {
@@ -318,26 +324,36 @@ olsr_timer_walk(void)
                   timer->info->name,
                   timer, timer->cb_context, _next_fire_event);
 
-       /* This timer is expired, call into the provided callback function */
-       timer->info->callback(timer->cb_context);
-       timer->info->changes++;
-
-       /*
-        * Only act on actually running timers, the callback might have
-        * called olsr_timer_stop() !
-        */
-       if (!timer->_clock) {
-         /* Timer has been stopped by callback */
-         continue;
-       }
-       if (timer->period) {
-         /* For periodical timers, rehash the random number and restart */
-         timer->_random = random();
-         olsr_timer_start(timer, timer->period);
-       } else {
-         /* Singleshot timers are stopped */
-         olsr_timer_stop(timer);
-       }
+      /*
+       * The timer->info pointer is invalidated by olsr_timer_stop()
+       */
+      info = timer->info;
+      info->_timer_in_callback = timer;
+      info->_timer_stopped = false;
+
+      /* update statistics */
+      info->changes++;
+
+      if (timer->period == 0) {
+        /* stop now, the data structure might not be available anymore later */
+        olsr_timer_stop(timer);
+      }
+
+      /* This timer is expired, call into the provided callback function */
+      timer->info->callback(timer->cb_context);
+
+      /*
+       * Only act on actually running timers, the callback might have
+       * called olsr_timer_stop() !
+       */
+      if (!info->_timer_stopped) {
+        /*
+         * Timer has been not been stopped, so its periodic
+         * rehash the random number and restart
+         */
+        timer->_random = random();
+        olsr_timer_start(timer, timer->period);
+      }
     }
 
     /* advance our 'next event' marker */
index 8a97d89..5809e69 100644 (file)
 /* prototype for timer callback */
 typedef void (*timer_cb_func) (void *);
 
+struct olsr_timer_entry;
+
 /*
  * This struct defines a class of timers which have the same
  * type (periodic/non-periodic) and callback.
  */
 struct olsr_timer_info {
-  /* node of timerinfo list */
-  struct list_entity node;
+  /* _node of timerinfo list */
+  struct list_entity _node;
 
   /* name of this timer class */
   const char *name;
@@ -71,6 +73,12 @@ struct olsr_timer_info {
 
   /* Stats, resource churn */
   uint32_t changes;
+
+  /* pointer to timer currently in callback */
+  struct olsr_timer_entry *_timer_in_callback;
+
+  /* set to true if the current running timer has been stopped */
+  bool _timer_stopped;
 };
 
 
@@ -102,12 +110,11 @@ struct olsr_timer_entry {
 
   /* absolute timestamp when timer will fire */
   uint64_t _clock;
-
 };
 
 /* Timers */
 EXPORT extern struct list_entity timerinfo_list;
-#define OLSR_FOR_ALL_TIMERS(ti, iterator) list_for_each_element_safe(&timerinfo_list, ti, node, iterator)
+#define OLSR_FOR_ALL_TIMERS(ti, iterator) list_for_each_element_safe(&timerinfo_list, ti, _node, iterator)
 
 EXPORT void olsr_timer_init(void);
 EXPORT void olsr_timer_cleanup(void);