]> git.ipfire.org Git - thirdparty/plymouth.git/commitdiff
[event-loop] Don't crash by running removed timeouts
authorRay Strode <rstrode@redhat.com>
Tue, 5 May 2009 15:57:21 +0000 (11:57 -0400)
committerRay Strode <rstrode@redhat.com>
Wed, 20 May 2009 21:00:27 +0000 (17:00 -0400)
We used to run and remove timeouts in a loop.  This
breaks the case where the dispatched timeout handler
removes the timeout itself.

We fix it by making timeout handling a two pass thing.
First we find which handlers need to be dispatched,
and move them to their own list.  Then we run through
the new list and dispatch the handlers.

src/libply/ply-event-loop.c

index 5bfd4062b77ef3301b2ba807c8e30946bc413885..8f6b304411869d087df2b88f992e81e9eac3e21e 100644 (file)
@@ -1123,6 +1123,7 @@ ply_event_loop_disconnect_source (ply_event_loop_t           *loop,
 static void
 ply_event_loop_handle_timeouts (ply_event_loop_t *loop)
 {
+  ply_list_t *watches_to_dispatch;
   ply_list_node_t *node;
   double now;
 
@@ -1130,6 +1131,8 @@ ply_event_loop_handle_timeouts (ply_event_loop_t *loop)
 
   now = ply_get_timestamp ();
   node = ply_list_get_first_node (loop->timeout_watches);
+
+  watches_to_dispatch = ply_list_new ();
   loop->wakeup_time = PLY_EVENT_LOOP_NO_TIMED_WAKEUP;
   while (node != NULL)
     {
@@ -1142,8 +1145,7 @@ ply_event_loop_handle_timeouts (ply_event_loop_t *loop)
       if (watch->timeout <= now)
         {
           assert (watch->handler != NULL);
-          watch->handler (watch->user_data, loop);
-          free (watch);
+          ply_list_append_data (watches_to_dispatch, watch);
           ply_list_remove_node (loop->timeout_watches, node);
         }
       else {
@@ -1156,6 +1158,23 @@ ply_event_loop_handle_timeouts (ply_event_loop_t *loop)
       node = next_node;
     }
 
+  node = ply_list_get_first_node (watches_to_dispatch);
+  while (node != NULL)
+    {
+      ply_list_node_t *next_node;
+      ply_event_loop_timeout_watch_t *watch;
+
+      watch = (ply_event_loop_timeout_watch_t *) ply_list_node_get_data (node);
+      next_node = ply_list_get_next_node (loop->timeout_watches, node);
+
+      watch->handler (watch->user_data, loop);
+      free (watch);
+
+      node = next_node;
+    }
+
+  ply_list_free (watches_to_dispatch);
+
 }
 
 static void