Fix idle_exiters when using recursive main loops.
authorbarbieri <barbieri@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Tue, 23 Feb 2010 22:25:35 +0000 (22:25 +0000)
committerbarbieri <barbieri@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Tue, 23 Feb 2010 22:25:35 +0000 (22:25 +0000)
commitcddcc3edfc2635e8b9fa199a00ed8cca610a20cf
tree70c440a9a5156e79aa64f91e6cb918557a07465b
parent8c99fcb7ad51458173bfef672e63f778e7135b56
Fix idle_exiters when using recursive main loops.

If an idle_exiter created a recursive main loop (just called
ecore_main_loop_begin()), then this recursive main loop should
continue to process idle_exiters from there and on, thus
idle_exiter_current was added. When going back from recursion, the
current iterator should be updated properly.

This patch also fixes the deletion of idle_exiters 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 <Ecore.h>
#include <Eina.h>

static int _log_dom;
#define INF(...) EINA_LOG_DOM_INFO(_log_dom, __VA_ARGS__)

static Ecore_Idle_Exiter *handle;

static int idler(void *data)
{
    INF("idler");
    return 1;
}

static int timer(void *data)
{
    INF("timer (exited idle!)");
    return 0;
}

static int exit_idle(void *data)
{
    INF("add request (timer) to exit idle");
    ecore_timer_add(0.0, timer, NULL);
    return 0;
}

static int cb2(void *data)
{
    INF("cb2 - delete cb1 handle");
    ecore_idle_exiter_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_exiter_add(cb2, NULL);
    INF("    add exit idler");
    ecore_idler_add(exit_idle, NULL);
    INF("    inner main loop begin (recurse)");
    ecore_main_loop_begin(); /* will it crash due ecore_idle_exiter_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_exiter 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_exiter_add(cb1, NULL);
    ecore_idler_add(idler, NULL);
    ecore_idler_add(exit_idle, NULL);
    ecore_main_loop_begin();
    INF("main: end");
    return 0;
}

git-svn-id: http://svn.enlightenment.org/svn/e/trunk/ecore@46410 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33
src/lib/ecore/ecore_idle_exiter.c