From: Ray Strode Date: Tue, 5 May 2009 15:57:21 +0000 (-0400) Subject: [event-loop] Don't crash by running removed timeouts X-Git-Tag: 0.7.0~190 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=79baa323e61b4c8a0e7bf75c773e78094ebf27fa;p=thirdparty%2Fplymouth.git [event-loop] Don't crash by running removed timeouts 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. --- diff --git a/src/libply/ply-event-loop.c b/src/libply/ply-event-loop.c index 5bfd4062..8f6b3044 100644 --- a/src/libply/ply-event-loop.c +++ b/src/libply/ply-event-loop.c @@ -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