From 0bdbf9d147bf130cd77ddd2067480d7a3fe6db2f Mon Sep 17 00:00:00 2001 From: Gustavo Sverzut Barbieri Date: Wed, 24 Feb 2010 00:27:04 +0000 Subject: [PATCH] rewrite ecore_timer internals to make it simpler and do better with recursive main loops. Unlike idlers, timers seems to work reasonably well with main loops, I *think* they might fail since it used a boolean to flag running as opposed to a reference count with incremental increments/decrements. I could not write a test case to demonstrate so. The now code should be simpler, particularly the _ecore_timer_call(). It will also consider the previous position when entering recursive main loops, preserving the order. Deletion of timers are delegated to ecore_main.c, that was already calling _ecore_timer_cleanup() after timers were executed. SVN revision: 46416 --- legacy/ecore/src/lib/ecore/ecore_timer.c | 115 ++++++++++++++--------- 1 file changed, 71 insertions(+), 44 deletions(-) diff --git a/legacy/ecore/src/lib/ecore/ecore_timer.c b/legacy/ecore/src/lib/ecore/ecore_timer.c index 9781bf680e..8d13c065be 100644 --- a/legacy/ecore/src/lib/ecore/ecore_timer.c +++ b/legacy/ecore/src/lib/ecore/ecore_timer.c @@ -23,10 +23,10 @@ struct _Ecore_Timer int (*func) (void *data); void *data; + int references; unsigned char delete_me : 1; unsigned char just_added : 1; unsigned char frozen : 1; - unsigned char running : 1; }; @@ -35,6 +35,7 @@ static void _ecore_timer_set(Ecore_Timer *timer, double at, double in, int (*fun static int timers_added = 0; static int timers_delete_me = 0; static Ecore_Timer *timers = NULL; +static Ecore_Timer *timer_current = NULL; static Ecore_Timer *suspended = NULL; static double last_check = 0.0; static double precision = 10.0 / 1000000.0; @@ -176,7 +177,7 @@ ecore_timer_del(Ecore_Timer *timer) return NULL; } - if (timer->frozen && !timer->running) + if (timer->frozen && !timer->references) { void *data = timer->data; @@ -309,8 +310,7 @@ ecore_timer_freeze(Ecore_Timer *timer) if (timer->frozen) return ; - if (!timer->running) - timers = (Ecore_Timer *) eina_inlist_remove(EINA_INLIST_GET(timers), EINA_INLIST_GET(timer)); + timers = (Ecore_Timer *) eina_inlist_remove(EINA_INLIST_GET(timers), EINA_INLIST_GET(timer)); suspended = (Ecore_Timer *) eina_inlist_prepend(EINA_INLIST_GET(suspended), EINA_INLIST_GET(timer)); now = ecore_time_get(); @@ -360,12 +360,15 @@ _ecore_timer_shutdown(void) ECORE_MAGIC_SET(timer, ECORE_MAGIC_NONE); free(timer); } + + timer_current = NULL; } void _ecore_timer_cleanup(void) { Ecore_Timer *l; + int in_use = 0; if (!timers_delete_me) return; for (l = timers; l;) @@ -375,6 +378,11 @@ _ecore_timer_cleanup(void) l = (Ecore_Timer *) EINA_INLIST_GET(l)->next; if (timer->delete_me) { + if (timer->references) + { + in_use++; + continue; + } timers = (Ecore_Timer *) eina_inlist_remove(EINA_INLIST_GET(timers), EINA_INLIST_GET(timer)); ECORE_MAGIC_SET(timer, ECORE_MAGIC_NONE); free(timer); @@ -389,6 +397,11 @@ _ecore_timer_cleanup(void) l = (Ecore_Timer *) EINA_INLIST_GET(l)->next; if (timer->delete_me) { + if (timer->references) + { + in_use++; + continue; + } suspended = (Ecore_Timer *) eina_inlist_remove(EINA_INLIST_GET(suspended), EINA_INLIST_GET(timer)); ECORE_MAGIC_SET(timer, ECORE_MAGIC_NONE); free(timer); @@ -396,7 +409,13 @@ _ecore_timer_cleanup(void) if (timers_delete_me == 0) return; } } - timers_delete_me = 0; + + if ((!in_use) && (timers_delete_me)) + { + ERR("%d timers to delete, but they were not found! reset counter.", + timers_delete_me); + timers_delete_me = 0; + } } void @@ -469,58 +488,66 @@ _ecore_timer_next_get(void) int _ecore_timer_call(double when) { - Ecore_Timer *timer, *l; - if (!timers) return 0; if (last_check > when) { + Ecore_Timer *timer; /* User set time backwards */ EINA_INLIST_FOREACH(timers, timer) timer->at -= (last_check - when); } last_check = when; - for (l = timers; l;) + + if (!timer_current) { - timer = l; - l = (Ecore_Timer *) EINA_INLIST_GET(l)->next; -// printf("_ecore_timer_call %3.3f <= %3.3f %i %i %p\n", -// timer->at, when, timer->just_added, timer->delete_me, timer); - if ((timer->at <= when) && - (timer->just_added == 0) && - (timer->delete_me == 0)) + /* regular main loop, start from head */ + timer_current = timers; + } + else + { + /* recursive main loop, continue from where we were */ + timer_current = (Ecore_Timer *)EINA_INLIST_GET(timer_current)->next; + } + + while (timer_current) + { + Ecore_Timer *timer = timer_current; + + if (timer->at > when) { - timer->running = EINA_TRUE; + timer_current = NULL; /* ended walk, next should restart. */ + return 0; + } + if ((timer->just_added) || (timer->delete_me)) + { + timer_current = (Ecore_Timer*)EINA_INLIST_GET(timer_current)->next; + continue; + } + + timer->references++; + if (!timer->func(timer->data)) ecore_timer_del(timer); + timer->references--; + + if (timer_current) /* may have changed in recursive main loops */ + timer_current = (Ecore_Timer *)EINA_INLIST_GET(timer_current)->next; + + if ((!timer->delete_me) && (!timer->frozen)) + { timers = (Ecore_Timer *) eina_inlist_remove(EINA_INLIST_GET(timers), EINA_INLIST_GET(timer)); - if ((!timer->delete_me) && (timer->func(timer->data))) - { - /* if the timer would have gone off more than 15 seconds ago, - * assume that the system hung and set the timer to go off - * timer->in from now. this handles system hangs, suspends - * and more, so ecore will only "replay" the timers while - * the system is suspended if it is suspended for less than - * 15 seconds (basically). this also handles if the process - * is stopped in a debugger or IO and other handling gets - * really slow within the main loop. - */ - if (!timer->delete_me) - { - timer->running = EINA_FALSE; - if (!timer->frozen) - { - if ((timer->at + timer->in) < (when - 15.0)) - _ecore_timer_set(timer, when + timer->in, timer->in, timer->func, timer->data); - else - _ecore_timer_set(timer, timer->at + timer->in, timer->in, timer->func, timer->data); - } - } - else - free(timer); - } + /* if the timer would have gone off more than 15 seconds ago, + * assume that the system hung and set the timer to go off + * timer->in from now. this handles system hangs, suspends + * and more, so ecore will only "replay" the timers while + * the system is suspended if it is suspended for less than + * 15 seconds (basically). this also handles if the process + * is stopped in a debugger or IO and other handling gets + * really slow within the main loop. + */ + if ((timer->at + timer->in) < (when - 15.0)) + _ecore_timer_set(timer, when + timer->in, timer->in, timer->func, timer->data); else - free(timer); - _ecore_timer_call(when); - return 1; + _ecore_timer_set(timer, timer->at + timer->in, timer->in, timer->func, timer->data); } } return 0;