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
This commit is contained in:
Gustavo Sverzut Barbieri 2010-02-24 00:27:04 +00:00
parent 34f6da920a
commit 0bdbf9d147
1 changed files with 71 additions and 44 deletions

View File

@ -23,10 +23,10 @@ struct _Ecore_Timer
int (*func) (void *data); int (*func) (void *data);
void *data; void *data;
int references;
unsigned char delete_me : 1; unsigned char delete_me : 1;
unsigned char just_added : 1; unsigned char just_added : 1;
unsigned char frozen : 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_added = 0;
static int timers_delete_me = 0; static int timers_delete_me = 0;
static Ecore_Timer *timers = NULL; static Ecore_Timer *timers = NULL;
static Ecore_Timer *timer_current = NULL;
static Ecore_Timer *suspended = NULL; static Ecore_Timer *suspended = NULL;
static double last_check = 0.0; static double last_check = 0.0;
static double precision = 10.0 / 1000000.0; static double precision = 10.0 / 1000000.0;
@ -176,7 +177,7 @@ ecore_timer_del(Ecore_Timer *timer)
return NULL; return NULL;
} }
if (timer->frozen && !timer->running) if (timer->frozen && !timer->references)
{ {
void *data = timer->data; void *data = timer->data;
@ -309,8 +310,7 @@ ecore_timer_freeze(Ecore_Timer *timer)
if (timer->frozen) if (timer->frozen)
return ; 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)); suspended = (Ecore_Timer *) eina_inlist_prepend(EINA_INLIST_GET(suspended), EINA_INLIST_GET(timer));
now = ecore_time_get(); now = ecore_time_get();
@ -360,12 +360,15 @@ _ecore_timer_shutdown(void)
ECORE_MAGIC_SET(timer, ECORE_MAGIC_NONE); ECORE_MAGIC_SET(timer, ECORE_MAGIC_NONE);
free(timer); free(timer);
} }
timer_current = NULL;
} }
void void
_ecore_timer_cleanup(void) _ecore_timer_cleanup(void)
{ {
Ecore_Timer *l; Ecore_Timer *l;
int in_use = 0;
if (!timers_delete_me) return; if (!timers_delete_me) return;
for (l = timers; l;) for (l = timers; l;)
@ -375,6 +378,11 @@ _ecore_timer_cleanup(void)
l = (Ecore_Timer *) EINA_INLIST_GET(l)->next; l = (Ecore_Timer *) EINA_INLIST_GET(l)->next;
if (timer->delete_me) if (timer->delete_me)
{ {
if (timer->references)
{
in_use++;
continue;
}
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));
ECORE_MAGIC_SET(timer, ECORE_MAGIC_NONE); ECORE_MAGIC_SET(timer, ECORE_MAGIC_NONE);
free(timer); free(timer);
@ -389,6 +397,11 @@ _ecore_timer_cleanup(void)
l = (Ecore_Timer *) EINA_INLIST_GET(l)->next; l = (Ecore_Timer *) EINA_INLIST_GET(l)->next;
if (timer->delete_me) if (timer->delete_me)
{ {
if (timer->references)
{
in_use++;
continue;
}
suspended = (Ecore_Timer *) eina_inlist_remove(EINA_INLIST_GET(suspended), EINA_INLIST_GET(timer)); suspended = (Ecore_Timer *) eina_inlist_remove(EINA_INLIST_GET(suspended), EINA_INLIST_GET(timer));
ECORE_MAGIC_SET(timer, ECORE_MAGIC_NONE); ECORE_MAGIC_SET(timer, ECORE_MAGIC_NONE);
free(timer); free(timer);
@ -396,7 +409,13 @@ _ecore_timer_cleanup(void)
if (timers_delete_me == 0) return; 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 void
@ -469,58 +488,66 @@ _ecore_timer_next_get(void)
int int
_ecore_timer_call(double when) _ecore_timer_call(double when)
{ {
Ecore_Timer *timer, *l;
if (!timers) return 0; if (!timers) return 0;
if (last_check > when) if (last_check > when)
{ {
Ecore_Timer *timer;
/* User set time backwards */ /* User set time backwards */
EINA_INLIST_FOREACH(timers, timer) timer->at -= (last_check - when); EINA_INLIST_FOREACH(timers, timer) timer->at -= (last_check - when);
} }
last_check = when; last_check = when;
for (l = timers; l;)
if (!timer_current)
{ {
timer = l; /* regular main loop, start from head */
l = (Ecore_Timer *) EINA_INLIST_GET(l)->next; timer_current = timers;
// printf("_ecore_timer_call %3.3f <= %3.3f %i %i %p\n", }
// timer->at, when, timer->just_added, timer->delete_me, timer); else
if ((timer->at <= when) && {
(timer->just_added == 0) && /* recursive main loop, continue from where we were */
(timer->delete_me == 0)) 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)); 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 the timer would have gone off more than 15 seconds ago,
{ * assume that the system hung and set the timer to go off
if ((timer->at + timer->in) < (when - 15.0)) * timer->in from now. this handles system hangs, suspends
_ecore_timer_set(timer, when + timer->in, timer->in, timer->func, timer->data); * and more, so ecore will only "replay" the timers while
else * the system is suspended if it is suspended for less than
_ecore_timer_set(timer, timer->at + timer->in, timer->in, timer->func, timer->data); * 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.
else */
free(timer); if ((timer->at + timer->in) < (when - 15.0))
} _ecore_timer_set(timer, when + timer->in, timer->in, timer->func, timer->data);
else else
free(timer); _ecore_timer_set(timer, timer->at + timer->in, timer->in, timer->func, timer->data);
_ecore_timer_call(when);
return 1;
} }
} }
return 0; return 0;