From 1c3348513a187c1c3b447d99e15e1dea9863a63a Mon Sep 17 00:00:00 2001 From: Gustavo Sverzut Barbieri Date: Tue, 23 Feb 2010 22:13:42 +0000 Subject: [PATCH] Fix idle_enterers when using recursive main loops. If an idle_enterer created a recursive main loop (just called ecore_main_loop_begin()), then this recursive main loop should continue to process idle_enterers from there and on, thus idle_enterer_current was added. When going back from recursion, the current iterator should be updated properly. This patch also fixes the deletion of idle_enterers from recursive main loops by reference counting them. This way, the node will not be free()d inside inner loop cleanups and then crash when going back to outer loop. The following test case used to crash but not anymore: #include #include static int _log_dom; #define INF(...) EINA_LOG_DOM_INFO(_log_dom, __VA_ARGS__) static Ecore_Idle_Enterer *handle; static int idler(void *data) { INF("idler"); return 1; } static int cb2(void *data) { INF("cb2 - delete cb1 handle"); ecore_idle_enterer_del(handle); ecore_main_loop_quit(); /* quits inner main loop */ return 0; } static int cb1(void *data) { INF("cb1: begin"); INF(" add cb2"); ecore_idle_enterer_add(cb2, NULL); INF(" inner main loop begin (recurse)"); ecore_main_loop_begin(); /* will it crash due ecore_idle_enterer_del(handle) * inside cb2()? It used to! */ INF("cb1: end"); ecore_main_loop_quit(); /* quits outer main loop */ return 0; } int main(void) { ecore_init(); _log_dom = eina_log_domain_register("test", EINA_COLOR_CYAN); /* * Creating a new main loop from inside an idle_enterer callback, * and inside this new (inner) main loop deleting the caller * callback used to crash since the handle would be effectively * free()d, but when the recursion is over the pointer would be * used. */ INF("main: begin"); handle = ecore_idle_enterer_add(cb1, NULL); ecore_idler_add(idler, NULL); ecore_main_loop_begin(); INF("main: end"); return 0; } SVN revision: 46408 --- .../ecore/src/lib/ecore/ecore_idle_enterer.c | 42 +++++++++++++++---- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/legacy/ecore/src/lib/ecore/ecore_idle_enterer.c b/legacy/ecore/src/lib/ecore/ecore_idle_enterer.c index 683a6f0fa6..2f9a5923a7 100644 --- a/legacy/ecore/src/lib/ecore/ecore_idle_enterer.c +++ b/legacy/ecore/src/lib/ecore/ecore_idle_enterer.c @@ -16,13 +16,15 @@ struct _Ecore_Idle_Enterer { EINA_INLIST; ECORE_MAGIC; - int delete_me : 1; int (*func) (void *data); void *data; + int references; + Eina_Bool delete_me : 1; }; static Ecore_Idle_Enterer *idle_enterers = NULL; +static Ecore_Idle_Enterer *idle_enterer_current = NULL; static int idle_enterers_delete_me = 0; /** @@ -103,35 +105,61 @@ _ecore_idle_enterer_shutdown(void) free(ie); } idle_enterers_delete_me = 0; + idle_enterer_current = NULL; } void _ecore_idle_enterer_call(void) { - Ecore_Idle_Enterer *ie; - - EINA_INLIST_FOREACH(idle_enterers, ie) + if (!idle_enterer_current) { + /* regular main loop, start from head */ + idle_enterer_current = idle_enterers; + } + else + { + /* recursive main loop, continue from where we were */ + idle_enterer_current = + (Ecore_Idle_Enterer *)EINA_INLIST_GET(idle_enterer_current)->next; + } + + while (idle_enterer_current) + { + Ecore_Idle_Enterer *ie = (Ecore_Idle_Enterer *)idle_enterer_current; if (!ie->delete_me) { + ie->references++; if (!ie->func(ie->data)) ecore_idle_enterer_del(ie); + ie->references--; } + if (idle_enterer_current) /* may have changed in recursive main loops */ + idle_enterer_current = + (Ecore_Idle_Enterer *)EINA_INLIST_GET(idle_enterer_current)->next; } if (idle_enterers_delete_me) { Ecore_Idle_Enterer *l; - for(l = idle_enterers; l;) + int deleted_idler_enterers_in_use = 0; + + for (l = idle_enterers; l;) { - ie = l; + Ecore_Idle_Enterer *ie = l; l = (Ecore_Idle_Enterer *) EINA_INLIST_GET(l)->next; if (ie->delete_me) { + if (ie->references) + { + deleted_idler_enterers_in_use++; + continue; + } + idle_enterers = (Ecore_Idle_Enterer *) eina_inlist_remove(EINA_INLIST_GET(idle_enterers), EINA_INLIST_GET(ie)); ECORE_MAGIC_SET(ie, ECORE_MAGIC_NONE); free(ie); } } - idle_enterers_delete_me = 0; + if (!deleted_idler_enterers_in_use) + idle_enterers_delete_me = 0; } }