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);
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;