Fix race circular cleanup between handlers
authorHenning Rogge <henning.rogge@fkie.fraunhofer.de>
Fri, 24 Feb 2012 15:16:14 +0000 (16:16 +0100)
committerHenning Rogge <henning.rogge@fkie.fraunhofer.de>
Fri, 24 Feb 2012 15:16:14 +0000 (16:16 +0100)
lib/remotecontrol/src/remotecontrol.c
src/core/olsr_telnet.c
src/core/os_linux/os_routing_linux.c

index e2f6bb9..e21cdc3 100644 (file)
@@ -566,11 +566,11 @@ _cb_handle_config(struct olsr_telnet_data *data) {
  * @param session
  */
 static void
-_stop_route_feedback(struct olsr_telnet_data *session) {
-  struct os_route *route;
+_cb_route_stophandler(struct olsr_telnet_data *data) {
+  struct _remotecontrol_session *session;
 
-  route = session->stop_data[0];
-  os_routing_interrupt(route);
+  session = data->stop_data[0];
+  os_routing_interrupt(&session->route);
 }
 
 /**
@@ -591,7 +591,8 @@ _cb_route_finished(struct os_route *rt, int error) {
   else {
     abuf_puts(session->cleanup.data->out, "Command successful\n");
   }
-  olsr_telnet_flush_session(session->cleanup.data);
+
+  session->route.cb_finished = NULL;
   olsr_telnet_stop(session->cleanup.data);
 }
 
@@ -765,7 +766,7 @@ _cb_handle_route(struct olsr_telnet_data *data) {
       return TELNET_RESULT_ACTIVE;
     }
 
-    data->stop_handler = _stop_route_feedback;
+    data->stop_handler = _cb_route_stophandler;
     data->stop_data[0] = session;
     return TELNET_RESULT_CONTINOUS;
   }
index 2f4a9e1..0e0466d 100644 (file)
@@ -22,6 +22,7 @@
 #include "olsr_telnet.h"
 
 /* static function prototypes */
+static void _call_stop_handler(struct olsr_telnet_data *data);
 static void _cb_config_changed(void);
 static int _cb_telnet_init(struct olsr_stream_session *);
 static void _cb_telnet_cleanup(struct olsr_stream_session *);
@@ -175,10 +176,7 @@ olsr_telnet_remove(struct olsr_telnet_command *command) {
 
 void
 olsr_telnet_stop(struct olsr_telnet_data *data) {
-  if (data->stop_handler) {
-    data->stop_handler(data);
-    data->stop_handler = NULL;
-  }
+  _call_stop_handler(data);
   data->show_echo = true;
   abuf_puts(data->out, "> ");
   olsr_telnet_flush_session(data);
@@ -304,6 +302,18 @@ _cb_telnet_create_error(struct olsr_stream_session *session,
   }
 }
 
+/* handle clean call of stop handler */
+static void
+_call_stop_handler(struct olsr_telnet_data *data) {
+  void (*stop_handler)(struct olsr_telnet_data *);
+
+  if (data->stop_handler) {
+    stop_handler = data->stop_handler;
+    data->stop_handler = NULL;
+    stop_handler(data);
+  }
+}
+
 /**
  * Handler for receiving data from telnet session
  * @param session pointer to TCP session
@@ -371,10 +381,7 @@ _cb_telnet_receive_data(struct olsr_stream_session *session) {
       }
 
       /* if we are doing continous output, stop it ! */
-      if (telnet_session->data.stop_handler) {
-        telnet_session->data.stop_handler(&telnet_session->data);
-        telnet_session->data.stop_handler = NULL;
-      }
+      _call_stop_handler(&telnet_session->data);
 
       if (strlen(cmd) != 0) {
         OLSR_DEBUG(LOG_TELNET, "Processing telnet command: '%s' '%s'",
@@ -600,7 +607,7 @@ _cb_telnet_repeat_timer(void *ptr) {
   telnet_data->parameter = telnet_data->stop_data[2];
 
   if (_telnet_handle_command(telnet_data) != TELNET_RESULT_ACTIVE) {
-    telnet_data->stop_handler(telnet_data);
+    _call_stop_handler(telnet_data);
   }
 
   /* reconstruct original session pointer */
@@ -652,7 +659,7 @@ _cb_telnet_repeat(struct olsr_telnet_data *data) {
   data->parameter = data->stop_data[2];
 
   if (_telnet_handle_command(data) != TELNET_RESULT_ACTIVE) {
-    data->stop_handler(data);
+    _call_stop_handler(data);
   }
 
   return TELNET_RESULT_CONTINOUS;
index f45f38c..bc9366a 100644 (file)
@@ -74,7 +74,7 @@ static int _routing_set(struct nlmsghdr *msg, struct os_route *route,
 static bool _is_at_least_linuxkernel_2_6_31(void);
 static int _os_linux_writeToProc(const char *file, char *old, char value);
 
-static void _routing_interrupt(struct os_route *route, int error);
+static void _routing_finished(struct os_route *route, int error);
 static void _cb_rtnetlink_message(struct nlmsghdr *);
 static void _cb_rtnetlink_error(uint32_t seq, int error);
 static void _cb_rtnetlink_done(uint32_t seq);
@@ -361,7 +361,7 @@ os_routing_query(struct os_route *route) {
  */
 void
 os_routing_interrupt(struct os_route *route) {
-  _routing_interrupt(route, -1);
+  _routing_finished(route, -1);
 }
 
 /**
@@ -371,11 +371,19 @@ os_routing_interrupt(struct os_route *route) {
  * @param error error code, 0 if no error
  */
 static void
-_routing_interrupt(struct os_route *route, int error) {
+_routing_finished(struct os_route *route, int error) {
   if (route->cb_finished) {
-    route->cb_finished(route, error);
+    void (*cb_finished)(struct os_route *, int error);
+
+    cb_finished = route->cb_finished;
+    route->cb_finished = NULL;
+
+    cb_finished(route, error);
+  }
+
+  if (list_is_node_added(&route->_internal._node)) {
+    list_remove(&route->_internal._node);
   }
-  list_remove(&route->_internal._node);
 }
 
 /**
@@ -601,7 +609,7 @@ _cb_rtnetlink_error(uint32_t seq, int error) {
 
   list_for_each_element(&_rtnetlink_feedback, route, _internal._node) {
     if (seq == route->_internal.nl_seq) {
-      _routing_interrupt(route, error);
+      _routing_finished(route, error);
       break;
     }
   }
@@ -617,7 +625,7 @@ _cb_rtnetlink_timeout(void) {
   OLSR_DEBUG(LOG_OS_ROUTING, "Got timeout");
 
   list_for_each_element_safe(&_rtnetlink_feedback, route, _internal._node, rt_it) {
-    _routing_interrupt(route, -1);
+    _routing_finished(route, -1);
   }
 }
 
@@ -633,7 +641,7 @@ _cb_rtnetlink_done(uint32_t seq) {
 
   list_for_each_element(&_rtnetlink_feedback, route, _internal._node) {
     if (seq == route->_internal.nl_seq) {
-      _routing_interrupt(route, 0);
+      _routing_finished(route, 0);
       break;
     }
   }