Tizen 2.1 base
[framework/uifw/ecore.git] / src / lib / ecore / ecore_timer.c
1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif
4
5 #include <stdlib.h>
6 #include <stdio.h>
7
8 #include "Ecore.h"
9 #include "ecore_private.h"
10
11 #ifdef WANT_ECORE_TIMER_DUMP
12 # include <string.h>
13 # include <execinfo.h>
14 # define ECORE_TIMER_DEBUG_BT_NUM 64
15 typedef void (*Ecore_Timer_Bt_Func)();
16 #endif
17
18 struct _Ecore_Timer
19 {
20    EINA_INLIST;
21                        ECORE_MAGIC;
22    double              in;
23    double              at;
24    double              pending;
25    Ecore_Task_Cb       func;
26    void               *data;
27
28 #ifdef WANT_ECORE_TIMER_DUMP
29    Ecore_Timer_Bt_Func timer_bt[ECORE_TIMER_DEBUG_BT_NUM];
30    int                 timer_bt_num;
31 #endif
32
33    int                 references;
34    unsigned char       delete_me : 1;
35    unsigned char       just_added : 1;
36    unsigned char       frozen : 1;
37 };
38 GENERIC_ALLOC_SIZE_DECLARE(Ecore_Timer);
39
40 static void _ecore_timer_set(Ecore_Timer  *timer,
41                              double        at,
42                              double        in,
43                              Ecore_Task_Cb func,
44                              void         *data);
45 #ifdef WANT_ECORE_TIMER_DUMP
46 static int _ecore_timer_cmp(const void *d1,
47                             const void *d2);
48 #endif
49
50 static int timers_added = 0;
51 static int timers_delete_me = 0;
52 static Ecore_Timer *timers = NULL;
53 static Ecore_Timer *timer_current = NULL;
54 static Ecore_Timer *suspended = NULL;
55 static double last_check = 0.0;
56 static double precision = 10.0 / 1000000.0;
57
58 /**
59  * @addtogroup Ecore_Timer_Group
60  *
61  * @{
62  */
63
64 /**
65  * Retrieves the current precision used by timer infrastructure.
66  * @return Current precision.
67  * @see ecore_timer_precision_set()
68  */
69 EAPI double
70 ecore_timer_precision_get(void)
71 {
72    EINA_MAIN_LOOP_CHECK_RETURN_VAL(0.0);
73    return precision;
74 }
75
76 /**
77  * @brief Sets the precision to be used by timer infrastructure.
78  *
79  * @param value allowed introduced timeout delay, in seconds.
80  *
81  * This sets the precision for @b all timers. The precision determines how much
82  * of an difference from the requested interval is acceptable. One common reason
83  * to use this function is to @b increase the allowed timeout and thus @b
84  * decrease precision of the timers, this is because less precise the timers
85  * result in the system waking up less often and thus consuming less resources.
86  *
87  * Be aware that kernel may delay delivery even further, these delays
88  * are always possible due other tasks having higher priorities or
89  * other scheduler policies.
90  *
91  * Example:
92  *  We have 2 timers, one that expires in a 2.0s and another that
93  *  expires in 2.1s, if precision is 0.1s, then the Ecore will request
94  *  for the next expire to happen in 2.1s and not 2.0s and another one
95  *  of 0.1 as it would before.
96  *
97  * @note Ecore is smart enough to see if there are timers in the
98  * precision range, if it does not, in our example if no second timer
99  * in (T + precision) existed, then it would use the minimum timeout.
100  */
101 EAPI void
102 ecore_timer_precision_set(double value)
103 {
104    EINA_MAIN_LOOP_CHECK_RETURN;
105    _ecore_lock();
106
107    if (value < 0.0)
108      {
109         ERR("Precision %f less than zero, ignored", value);
110         goto unlock;
111      }
112    precision = value;
113
114 unlock:
115    _ecore_unlock();
116 }
117
118 /**
119  * Creates a timer to call the given function in the given period of time.
120  * @param   in   The interval in seconds.
121  * @param   func The given function.  If @p func returns 1, the timer is
122  *               rescheduled for the next interval @p in.
123  * @param   data Data to pass to @p func when it is called.
124  * @return  A timer object on success.  @c NULL on failure.
125  *
126  * This function adds a timer and returns its handle on success and NULL on
127  * failure. The function @p func will be called every @p in seconds. The
128  * function will be passed the @p data pointer as its parameter.
129  *
130  * When the timer @p func is called, it must return a value of either 1
131  * (or ECORE_CALLBACK_RENEW) or 0 (or ECORE_CALLBACK_CANCEL).
132  * If it returns 1, it will be called again at the next tick, or if it returns
133  * 0 it will be deleted automatically making any references/handles for it
134  * invalid.
135  */
136 EAPI Ecore_Timer *
137 ecore_timer_add(double        in,
138                 Ecore_Task_Cb func,
139                 const void   *data)
140 {
141    double now;
142    Ecore_Timer *timer = NULL;
143
144    EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
145    _ecore_lock();
146    if (!func) goto unlock;
147    if (in < 0.0) in = 0.0;
148    timer = ecore_timer_calloc(1);
149    if (!timer) goto unlock;
150    ECORE_MAGIC_SET(timer, ECORE_MAGIC_TIMER);
151    now = ecore_time_get();
152
153 #ifdef WANT_ECORE_TIMER_DUMP
154    timer->timer_bt_num = backtrace((void **)(timer->timer_bt),
155                                    ECORE_TIMER_DEBUG_BT_NUM);
156 #endif
157
158    _ecore_timer_set(timer, now + in, in, func, (void *)data);
159 unlock:
160    _ecore_unlock();
161    return timer;
162 }
163
164 /**
165  * Creates a timer to call the given function in the given period of time.
166  * @param   in   The interval in seconds from current loop time.
167  * @param   func The given function.  If @p func returns 1, the timer is
168  *               rescheduled for the next interval @p in.
169  * @param   data Data to pass to @p func when it is called.
170  * @return  A timer object on success.  @c NULL on failure.
171  *
172  * This is the same as ecore_timer_add(), but "now" is the time from
173  * ecore_loop_time_get() not ecore_time_get() as ecore_timer_add() uses. See
174  * ecore_timer_add() for more details.
175  */
176 EAPI Ecore_Timer *
177 ecore_timer_loop_add(double        in,
178                      Ecore_Task_Cb func,
179                      const void   *data)
180 {
181    Ecore_Timer *timer;
182
183    EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
184    _ecore_lock();
185    timer = _ecore_timer_loop_add(in, func, data);
186    _ecore_unlock();
187
188    return timer;
189 }
190
191 /**
192  * Delete the specified timer from the timer list.
193  * @param   timer The timer to delete.
194  * @return  The data pointer set for the timer when @ref ecore_timer_add was
195  *          called.  @c NULL is returned if the function is unsuccessful.
196  *
197  * Note: @p timer must be a valid handle. If the timer function has already
198  * returned 0, the handle is no longer valid (and does not need to be delete).
199  */
200 EAPI void *
201 ecore_timer_del(Ecore_Timer *timer)
202 {
203    void *data = NULL;
204
205    EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
206    _ecore_lock();
207
208    if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER))
209      {
210         ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER,
211                          "ecore_timer_del");
212         goto unlock;
213      }
214
215    data = _ecore_timer_del(timer);
216
217 unlock:
218    _ecore_unlock();
219    return data;
220 }
221
222 /**
223  * Change the interval the timer ticks of. If set during
224  * a timer call, this will affect the next interval.
225  *
226  * @param   timer The timer to change.
227  * @param   in    The interval in seconds.
228  */
229 EAPI void
230 ecore_timer_interval_set(Ecore_Timer *timer,
231                          double       in)
232 {
233    EINA_MAIN_LOOP_CHECK_RETURN;
234    _ecore_lock();
235    if (in < 0.0) in = 0.0;
236    if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER))
237      {
238         ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER,
239                          "ecore_timer_interval_set");
240         goto unlock;
241      }
242    timer->in = in;
243 unlock:
244    _ecore_unlock();
245 }
246
247 /**
248  * Get the interval the timer ticks on.
249  *
250  * @param   timer The timer to retrieve the interval from
251  * @return  The interval on success. -1 on failure.
252  */
253 EAPI double
254 ecore_timer_interval_get(Ecore_Timer *timer)
255 {
256    double interval;
257
258    EINA_MAIN_LOOP_CHECK_RETURN_VAL(0.0);
259    _ecore_lock();
260
261    if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER))
262      {
263         ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER,
264                          "ecore_timer_interval_get");
265         interval = -1.0;
266         goto unlock;
267      }
268
269    interval = timer->in;
270 unlock:
271    _ecore_unlock();
272    return interval;
273 }
274
275 /**
276  * Add some delay for the next occurrence of a timer.
277  * This doesn't affect the interval of a timer.
278  *
279  * @param   timer The timer to change.
280  * @param   add   The delay to add to the next iteration.
281  */
282 EAPI void
283 ecore_timer_delay(Ecore_Timer *timer,
284                   double       add)
285 {
286    EINA_MAIN_LOOP_CHECK_RETURN;
287    if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER))
288      {
289         ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER,
290                          "ecore_timer_delay");
291         return;
292      }
293
294    _ecore_lock();
295    _ecore_timer_delay(timer, add);
296    _ecore_unlock();
297 }
298
299 /**
300  * Reset a timer to its full interval
301  * This doesn't affect the interval of a timer
302  * @param timer The timer
303  * @since 1.2
304  * @note This is equivalent to (but faster than)
305  * @code
306  * ecore_timer_delay(timer, ecore_timer_interval_get(timer) - ecore_timer_pending_get(timer));
307  * @endcode
308  */
309 EAPI void
310 ecore_timer_reset(Ecore_Timer *timer)
311 {
312    double now, add;
313    EINA_MAIN_LOOP_CHECK_RETURN;
314    if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER))
315      {
316         ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER,
317                          __func__);
318         return;
319      }
320    _ecore_lock();
321    now = ecore_time_get();
322
323    if (timer->frozen)
324      add = timer->pending;
325    else
326      add = timer->at - now;
327    _ecore_timer_delay(timer, timer->in - add);
328    _ecore_unlock();
329 }
330
331 /**
332  * Get the pending time regarding a timer.
333  *
334  * @param        timer The timer to learn from.
335  * @return The pending time.
336  * @ingroup        Ecore_Timer_Group
337  */
338 EAPI double
339 ecore_timer_pending_get(Ecore_Timer *timer)
340 {
341    double now;
342    double ret = 0.0;
343
344    EINA_MAIN_LOOP_CHECK_RETURN_VAL(0.0);
345    _ecore_lock();
346
347    if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER))
348      {
349         ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER,
350                          "ecore_timer_pending_get");
351         goto unlock;
352      }
353
354    now = ecore_time_get();
355
356    if (timer->frozen)
357      ret = timer->pending;
358    else
359      ret = timer->at - now;
360 unlock:
361    _ecore_unlock();
362    return ret;
363 }
364
365 /**
366  * Pauses a running timer.
367  *
368  * @param timer The timer to be paused.
369  *
370  * The timer callback won't be called while the timer is paused. The remaining
371  * time until the timer expires will be saved, so the timer can be resumed with
372  * that same remaining time to expire, instead of expiring instantly.  Use
373  * ecore_timer_thaw() to resume it.
374  *
375  * @note Nothing happens if the timer was already paused.
376  *
377  * @see ecore_timer_thaw()
378  */
379 EAPI void
380 ecore_timer_freeze(Ecore_Timer *timer)
381 {
382    double now;
383
384    EINA_MAIN_LOOP_CHECK_RETURN;
385    _ecore_lock();
386
387    if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER))
388      {
389         ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER,
390                          "ecore_timer_freeze");
391         goto unlock;
392      }
393
394    /* Timer already frozen */
395    if (timer->frozen)
396      goto unlock;
397
398    timers = (Ecore_Timer *)eina_inlist_remove(EINA_INLIST_GET(timers), EINA_INLIST_GET(timer));
399    suspended = (Ecore_Timer *)eina_inlist_prepend(EINA_INLIST_GET(suspended), EINA_INLIST_GET(timer));
400
401    now = ecore_time_get();
402
403    timer->pending = timer->at - now;
404    timer->at = 0.0;
405    timer->frozen = 1;
406 unlock:
407    _ecore_unlock();
408 }
409
410 /**
411  * Resumes a frozen (paused) timer.
412  *
413  * @param timer The timer to be resumed.
414  *
415  * The timer will be resumed from its previous relative position in time. That
416  * means, if it had X seconds remaining until expire when it was paused, it will
417  * be started now with those same X seconds remaining to expire again. But
418  * notice that the interval time won't be touched by this call or by
419  * ecore_timer_freeze().
420  *
421  * @see ecore_timer_freeze()
422  */
423 EAPI void
424 ecore_timer_thaw(Ecore_Timer *timer)
425 {
426    double now;
427
428    EINA_MAIN_LOOP_CHECK_RETURN;
429    _ecore_lock();
430
431    if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER))
432      {
433         ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER,
434                          "ecore_timer_thaw");
435         goto unlock;
436      }
437
438    /* Timer not frozen */
439    if (!timer->frozen)
440      goto unlock;
441
442    suspended = (Ecore_Timer *)eina_inlist_remove(EINA_INLIST_GET(suspended), EINA_INLIST_GET(timer));
443    now = ecore_time_get();
444
445    _ecore_timer_set(timer, timer->pending + now, timer->in, timer->func, timer->data);
446 unlock:
447    _ecore_unlock();
448 }
449
450 EAPI char *
451 ecore_timer_dump(void)
452 {
453 #ifdef WANT_ECORE_TIMER_DUMP
454    Eina_Strbuf *result;
455    char *out;
456    Ecore_Timer *tm;
457    Eina_List *tmp = NULL;
458    int living_timer = 0;
459    int unknow_timer = 0;
460
461    EINA_MAIN_LOOP_CHECK_RETURN(NULL);
462    _ecore_lock();
463    result = eina_strbuf_new();
464
465    EINA_INLIST_FOREACH(timers, tm)
466      tmp = eina_list_sorted_insert(tmp, _ecore_timer_cmp, tm);
467
468    EINA_LIST_FREE(tmp, tm)
469      {
470         char **strings;
471         int j;
472
473         if (!tm->frozen && !tm->delete_me)
474           living_timer++;
475
476         strings = backtrace_symbols((void **)tm->timer_bt, tm->timer_bt_num);
477         if (tm->timer_bt_num <= 0 || strings == NULL)
478           {
479              unknow_timer++;
480              continue;
481           }
482
483         eina_strbuf_append_printf(result, "*** timer: %f ***\n", tm->in);
484         if (tm->frozen)
485           eina_strbuf_append(result, "FROZEN\n");
486         if (tm->delete_me)
487           eina_strbuf_append(result, "DELETED\n");
488         for (j = 0; j < tm->timer_bt_num; j++)
489           eina_strbuf_append_printf(result, "%s\n", strings[j]);
490
491         free(strings);
492      }
493
494    eina_strbuf_append_printf(result, "\n***\nThere is %i living timer.\nWe did lost track of %i timers.\n", living_timer, unknow_timer);
495
496    out = eina_strbuf_string_steal(result);
497    eina_strbuf_free(result);
498    _ecore_unlock();
499
500    return out;
501 #else
502    return NULL;
503 #endif
504 }
505
506 /**
507  * @}
508  */
509
510 Ecore_Timer *
511 _ecore_timer_loop_add(double        in,
512                       Ecore_Task_Cb func,
513                       const void   *data)
514 {
515    double now;
516    Ecore_Timer *timer = NULL;
517
518    if (!func) return timer;
519    if (in < 0.0) in = 0.0;
520    timer = ecore_timer_calloc(1);
521    if (!timer) return timer;
522    ECORE_MAGIC_SET(timer, ECORE_MAGIC_TIMER);
523    now = ecore_loop_time_get();
524
525 #ifdef WANT_ECORE_TIMER_DUMP
526    timer->timer_bt_num = backtrace((void **)(timer->timer_bt),
527                                    ECORE_TIMER_DEBUG_BT_NUM);
528 #endif
529    _ecore_timer_set(timer, now + in, in, func, (void *)data);
530    return timer;
531 }
532
533 EAPI void
534 _ecore_timer_delay(Ecore_Timer *timer,
535                    double       add)
536 {
537    if (timer->frozen)
538      {
539         timer->pending += add;
540      }
541    else
542      {
543         timers = (Ecore_Timer *)eina_inlist_remove(EINA_INLIST_GET(timers), EINA_INLIST_GET(timer));
544         _ecore_timer_set(timer, timer->at + add, timer->in, timer->func, timer->data);
545      }
546 }
547
548 void *
549 _ecore_timer_del(Ecore_Timer *timer)
550 {
551    if (timer->frozen && !timer->references)
552      {
553         void *data = timer->data;
554
555         suspended = (Ecore_Timer *)eina_inlist_remove(EINA_INLIST_GET(suspended), EINA_INLIST_GET(timer));
556
557         if (timer->delete_me)
558           timers_delete_me--;
559
560         ecore_timer_mp_free(timer);
561         return data;
562      }
563
564    EINA_SAFETY_ON_TRUE_RETURN_VAL(timer->delete_me, NULL);
565    timer->delete_me = 1;
566    timers_delete_me++;
567    return timer->data;
568 }
569
570 void
571 _ecore_timer_shutdown(void)
572 {
573    Ecore_Timer *timer;
574
575    while ((timer = timers))
576      {
577         timers = (Ecore_Timer *)eina_inlist_remove(EINA_INLIST_GET(timers), EINA_INLIST_GET(timers));
578         ECORE_MAGIC_SET(timer, ECORE_MAGIC_NONE);
579         ecore_timer_mp_free(timer);
580      }
581
582    while ((timer = suspended))
583      {
584         suspended = (Ecore_Timer *)eina_inlist_remove(EINA_INLIST_GET(suspended), EINA_INLIST_GET(suspended));
585         ECORE_MAGIC_SET(timer, ECORE_MAGIC_NONE);
586         ecore_timer_mp_free(timer);
587      }
588
589    timer_current = NULL;
590 }
591
592 void
593 _ecore_timer_cleanup(void)
594 {
595    Ecore_Timer *l;
596    int in_use = 0, todo = timers_delete_me, done = 0;
597
598    if (!timers_delete_me) return;
599    for (l = timers; l; )
600      {
601         Ecore_Timer *timer = l;
602
603         l = (Ecore_Timer *)EINA_INLIST_GET(l)->next;
604         if (timer->delete_me)
605           {
606              if (timer->references)
607                {
608                   in_use++;
609                   continue;
610                }
611              timers = (Ecore_Timer *)eina_inlist_remove(EINA_INLIST_GET(timers), EINA_INLIST_GET(timer));
612              ECORE_MAGIC_SET(timer, ECORE_MAGIC_NONE);
613              ecore_timer_mp_free(timer);
614              timers_delete_me--;
615              done++;
616              if (timers_delete_me == 0) return;
617           }
618      }
619    for (l = suspended; l; )
620      {
621         Ecore_Timer *timer = l;
622
623         l = (Ecore_Timer *)EINA_INLIST_GET(l)->next;
624         if (timer->delete_me)
625           {
626              if (timer->references)
627                {
628                   in_use++;
629                   continue;
630                }
631              suspended = (Ecore_Timer *)eina_inlist_remove(EINA_INLIST_GET(suspended), EINA_INLIST_GET(timer));
632              ECORE_MAGIC_SET(timer, ECORE_MAGIC_NONE);
633              ecore_timer_mp_free(timer);
634              timers_delete_me--;
635              done++;
636              if (timers_delete_me == 0) return;
637           }
638      }
639
640    if ((!in_use) && (timers_delete_me))
641      {
642         ERR("%d timers to delete, but they were not found!"
643             "Stats: todo=%d, done=%d, pending=%d, in_use=%d. "
644             "reset counter.",
645             timers_delete_me, todo, done, todo - done, in_use);
646         timers_delete_me = 0;
647      }
648 }
649
650 void
651 _ecore_timer_enable_new(void)
652 {
653    Ecore_Timer *timer;
654
655    if (!timers_added) return;
656    timers_added = 0;
657    EINA_INLIST_FOREACH(timers, timer) timer->just_added = 0;
658 }
659
660 int
661 _ecore_timers_exists(void)
662 {
663    Ecore_Timer *timer = timers;
664
665    while ((timer) && (timer->delete_me))
666      timer = (Ecore_Timer *)EINA_INLIST_GET(timer)->next;
667
668    return !!timer;
669 }
670
671 static inline Ecore_Timer *
672 _ecore_timer_first_get(void)
673 {
674    Ecore_Timer *timer = timers;
675
676    while ((timer) && ((timer->delete_me) || (timer->just_added)))
677      timer = (Ecore_Timer *)EINA_INLIST_GET(timer)->next;
678
679    return timer;
680 }
681
682 static inline Ecore_Timer *
683 _ecore_timer_after_get(Ecore_Timer *base)
684 {
685    Ecore_Timer *timer = (Ecore_Timer *)EINA_INLIST_GET(base)->next;
686    Ecore_Timer *valid_timer = NULL;
687    double maxtime = base->at + precision;
688
689    while ((timer) && (timer->at < maxtime))
690      {
691         if (!((timer->delete_me) || (timer->just_added)))
692           valid_timer = timer;
693         timer = (Ecore_Timer *)EINA_INLIST_GET(timer)->next;
694      }
695
696    return valid_timer;
697 }
698
699 double
700 _ecore_timer_next_get(void)
701 {
702    double now;
703    double in;
704    Ecore_Timer *first, *second;
705
706    first = _ecore_timer_first_get();
707    if (!first) return -1;
708
709    second = _ecore_timer_after_get(first);
710    if (second) first = second;
711
712    now = ecore_loop_time_get();
713    in = first->at - now;
714    if (in < 0) in = 0;
715    return in;
716 }
717
718 static inline void
719 _ecore_timer_reschedule(Ecore_Timer *timer,
720                         double       when)
721 {
722    if ((timer->delete_me) || (timer->frozen)) return;
723
724    timers = (Ecore_Timer *)eina_inlist_remove(EINA_INLIST_GET(timers), EINA_INLIST_GET(timer));
725
726    /* if the timer would have gone off more than 15 seconds ago,
727     * assume that the system hung and set the timer to go off
728     * timer->in from now. this handles system hangs, suspends
729     * and more, so ecore will only "replay" the timers while
730     * the system is suspended if it is suspended for less than
731     * 15 seconds (basically). this also handles if the process
732     * is stopped in a debugger or IO and other handling gets
733     * really slow within the main loop.
734     */
735    if ((timer->at + timer->in) < (when - 15.0))
736      _ecore_timer_set(timer, when + timer->in, timer->in, timer->func, timer->data);
737    else
738      _ecore_timer_set(timer, timer->at + timer->in, timer->in, timer->func, timer->data);
739 }
740
741 /* assume that we hold the ecore lock when entering this function */
742 void
743 _ecore_timer_expired_timers_call(double when)
744 {
745    /* call the first expired timer until no expired timers exist */
746     while (_ecore_timer_expired_call(when)) ;
747 }
748
749 /* assume that we hold the ecore lock when entering this function */
750 int
751 _ecore_timer_expired_call(double when)
752 {
753    if (!timers) return 0;
754    if (last_check > when)
755      {
756         Ecore_Timer *timer;
757         /* User set time backwards */
758         EINA_INLIST_FOREACH(timers, timer) timer->at -= (last_check - when);
759      }
760    last_check = when;
761
762    if (!timer_current)
763      {
764         /* regular main loop, start from head */
765          timer_current = timers;
766      }
767    else
768      {
769         /* recursive main loop, continue from where we were */
770          Ecore_Timer *timer_old = timer_current;
771          timer_current = (Ecore_Timer *)EINA_INLIST_GET(timer_current)->next;
772          _ecore_timer_reschedule(timer_old, when);
773      }
774
775    while (timer_current)
776      {
777         Ecore_Timer *timer = timer_current;
778
779         if (timer->at > when)
780           {
781              timer_current = NULL; /* ended walk, next should restart. */
782              return 0;
783           }
784
785         if ((timer->just_added) || (timer->delete_me))
786           {
787              timer_current = (Ecore_Timer *)EINA_INLIST_GET(timer_current)->next;
788              continue;
789           }
790
791         timer->references++;
792         if (!_ecore_call_task_cb(timer->func, timer->data))
793           {
794              if (!timer->delete_me) _ecore_timer_del(timer);
795           }
796         timer->references--;
797
798         if (timer_current) /* may have changed in recursive main loops */
799           timer_current = (Ecore_Timer *)EINA_INLIST_GET(timer_current)->next;
800
801         _ecore_timer_reschedule(timer, when);
802      }
803    return 0;
804 }
805
806 static void
807 _ecore_timer_set(Ecore_Timer  *timer,
808                  double        at,
809                  double        in,
810                  Ecore_Task_Cb func,
811                  void         *data)
812 {
813    Ecore_Timer *t2;
814
815    timers_added = 1;
816    timer->at = at;
817    timer->in = in;
818    timer->func = func;
819    timer->data = data;
820    timer->just_added = 1;
821    timer->frozen = 0;
822    timer->pending = 0.0;
823    if (timers)
824      {
825         EINA_INLIST_REVERSE_FOREACH(EINA_INLIST_GET(timers), t2)
826           {
827              if (timer->at > t2->at)
828                {
829                   timers = (Ecore_Timer *)eina_inlist_append_relative(EINA_INLIST_GET(timers), EINA_INLIST_GET(timer), EINA_INLIST_GET(t2));
830                   return;
831                }
832           }
833      }
834    timers = (Ecore_Timer *)eina_inlist_prepend(EINA_INLIST_GET(timers), EINA_INLIST_GET(timer));
835 }
836
837 #ifdef WANT_ECORE_TIMER_DUMP
838 static int
839 _ecore_timer_cmp(const void *d1,
840                  const void *d2)
841 {
842    const Ecore_Timer *t1 = d1;
843    const Ecore_Timer *t2 = d2;
844
845    return (int)((t1->in - t2->in) * 100);
846 }
847 #endif