svn update: 60286 (latest:60286)
[profile/ivi/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
39
40 static void _ecore_timer_set(Ecore_Timer *timer, double at, double in, Ecore_Task_Cb func, void *data);
41 static int _ecore_timer_cmp(const void *d1, const void *d2);
42
43 static int          timers_added = 0;
44 static int          timers_delete_me = 0;
45 static Ecore_Timer *timers = NULL;
46 static Ecore_Timer *timer_current = NULL;
47 static Ecore_Timer *suspended = NULL;
48 static double       last_check = 0.0;
49 static double       precision = 10.0 / 1000000.0;
50
51 /**
52  * @addtogroup Ecore_Group Ecore - Main Loop and Job Functions.
53  *
54  * @{
55  */
56
57 /**
58  * @addtogroup Ecore_Time_Group Ecore Time functions
59  *
60  * Functions that deal with time.  These functions include those that simply
61  * retrieve it in a given format, and those that create events based on it.
62  *
63  * The timer allows callbacks to be called at specific intervals.
64  *
65  * @{
66  */
67
68 /**
69  * Retrieves the current precision used by timer infrastructure.
70  *
71  * @see ecore_timer_precision_set()
72  */
73 EAPI double
74 ecore_timer_precision_get(void)
75 {
76    return precision;
77 }
78
79 /**
80  * Sets the precision to be used by timer infrastructure.
81  *
82  * When system calculates time to expire the next timer we'll be able
83  * to delay the timer by the given amount so more timers will fit in
84  * the same dispatch, waking up the system less often and thus being
85  * able to save power.
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  * @param value allowed introduced timeout delay, in seconds.
102  */
103 EAPI void
104 ecore_timer_precision_set(double value)
105 {
106    if (value < 0.0)
107      {
108         ERR("Precision %f less than zero, ignored", value);
109         return;
110      }
111    precision = value;
112 }
113
114 /**
115  * Creates a timer to call the given function in the given period of time.
116  * @param   in   The interval in seconds.
117  * @param   func The given function.  If @p func returns 1, the timer is
118  *               rescheduled for the next interval @p in.
119  * @param   data Data to pass to @p func when it is called.
120  * @return  A timer object on success.  @c NULL on failure.
121  *
122  * This function adds a timer and returns its handle on success and NULL on
123  * failure. The function @p func will be called every @p in seconds. The
124  * function will be passed the @p data pointer as its parameter.
125  *
126  * When the timer @p func is called, it must return a value of either 1
127  * (or ECORE_CALLBACK_RENEW) or 0 (or ECORE_CALLBACK_CANCEL).
128  * If it returns 1, it will be called again at the next tick, or if it returns
129  * 0 it will be deleted automatically making any references/handles for it
130  * invalid.
131  */
132 EAPI Ecore_Timer *
133 ecore_timer_add(double in, Ecore_Task_Cb func, const void *data)
134 {
135    double now;
136    Ecore_Timer *timer;
137
138    if (!func) return NULL;
139    if (in < 0.0) in = 0.0;
140    timer = calloc(1, sizeof(Ecore_Timer));
141    if (!timer) return NULL;
142    ECORE_MAGIC_SET(timer, ECORE_MAGIC_TIMER);
143    now = ecore_time_get();
144
145 #ifdef WANT_ECORE_TIMER_DUMP
146    timer->timer_bt_num = backtrace((void**) (timer->timer_bt),
147                                    ECORE_TIMER_DEBUG_BT_NUM);
148 #endif
149
150    _ecore_timer_set(timer, now + in, in, func, (void *)data);
151    return timer;
152 }
153
154 /**
155  * Creates a timer to call the given function in the given period of time.
156  * @param   in   The interval in seconds from current loop time.
157  * @param   func The given function.  If @p func returns 1, the timer is
158  *               rescheduled for the next interval @p in.
159  * @param   data Data to pass to @p func when it is called.
160  * @return  A timer object on success.  @c NULL on failure.
161  *
162  * This is the same as ecore_timer_add(), but "now" is the time from
163  * ecore_loop_time_get() not ecore_time_get() as ecore_timer_add() uses. See
164  * ecore_timer_add() for more details.
165  */
166 EAPI Ecore_Timer *
167 ecore_timer_loop_add(double in, Ecore_Task_Cb func, const void *data)
168 {
169    double now;
170    Ecore_Timer *timer;
171
172    if (!func) return NULL;
173    if (in < 0.0) in = 0.0;
174    timer = calloc(1, sizeof(Ecore_Timer));
175    if (!timer) return NULL;
176    ECORE_MAGIC_SET(timer, ECORE_MAGIC_TIMER);
177    now = ecore_loop_time_get();
178
179 #ifdef WANT_ECORE_TIMER_DUMP
180    timer->timer_bt_num = backtrace((void**) (timer->timer_bt),
181                                    ECORE_TIMER_DEBUG_BT_NUM);
182 #endif
183
184    _ecore_timer_set(timer, now + in, in, func, (void *)data);
185    return timer;
186 }
187
188 /**
189  * Delete the specified timer from the timer list.
190  * @param   timer The timer to delete.
191  * @return  The data pointer set for the timer when @ref ecore_timer_add was
192  *          called.  @c NULL is returned if the function is unsuccessful.
193  *
194  * Note: @p timer must be a valid handle. If the timer function has already
195  * returned 0, the handle is no longer valid (and does not need to be delete).
196  */
197 EAPI void *
198 ecore_timer_del(Ecore_Timer *timer)
199 {
200    if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER))
201      {
202         ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER,
203                          "ecore_timer_del");
204         return NULL;
205      }
206
207    if (timer->frozen && !timer->references)
208      {
209         void *data = timer->data;
210
211         suspended = (Ecore_Timer *) eina_inlist_remove(EINA_INLIST_GET(suspended), EINA_INLIST_GET(timer));
212
213         if (timer->delete_me)
214           timers_delete_me--;
215
216         free(timer);
217         return data;
218      }
219
220    EINA_SAFETY_ON_TRUE_RETURN_VAL(timer->delete_me, NULL);
221    timer->delete_me = 1;
222    timers_delete_me++;
223    return timer->data;
224 }
225
226 /**
227  * Change the interval the timer ticks of. If set during
228  * a timer call, this will affect the next interval.
229  *
230  * @param   timer The timer to change.
231  * @param   in    The interval in seconds.
232  */
233 EAPI void
234 ecore_timer_interval_set(Ecore_Timer *timer, double in)
235 {
236    if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER))
237      {
238         ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER,
239                          "ecore_timer_interval_set");
240         return;
241      }
242    timer->in = in;
243 }
244
245 /**
246  * Get the interval the timer ticks on.
247  *
248  * @param   timer The timer to retrieve the interval from
249  * @return  The interval on success. -1 on failure.
250  */
251 EAPI double
252 ecore_timer_interval_get(Ecore_Timer *timer)
253 {
254    if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER))
255      {
256         ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER,
257                          "ecore_timer_interval_get");
258         return -1.0;
259      }
260
261    return timer->in;
262 }
263
264 /**
265  * Add some delay for the next occurrence of a timer.
266  * This doesn't affect the interval of a timer.
267  *
268  * @param   timer The timer to change.
269  * @param   add   The dalay to add to the next iteration.
270  */
271 EAPI void
272 ecore_timer_delay(Ecore_Timer *timer, double add)
273 {
274    if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER))
275      {
276         ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER,
277                          "ecore_timer_delay");
278         return;
279      }
280
281    if (timer->frozen)
282      {
283         timer->pending += add;
284      }
285    else
286      {
287         timers = (Ecore_Timer *) eina_inlist_remove(EINA_INLIST_GET(timers), EINA_INLIST_GET(timer));
288         _ecore_timer_set(timer, timer->at + add, timer->in, timer->func, timer->data);
289      }
290 }
291
292 /**
293  * Get the pending time regarding a timer.
294  *
295  * @param        timer The timer to learn from.
296  * @ingroup        Ecore_Time_Group
297  */
298 EAPI double
299 ecore_timer_pending_get(Ecore_Timer *timer)
300 {
301    double        now;
302
303    if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER))
304      {
305         ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER,
306                          "ecore_timer_pending_get");
307         return 0;
308      }
309
310    now = ecore_time_get();
311
312    if (timer->frozen)
313      return timer->pending;
314    return timer->at - now;
315 }
316
317 /**
318  *
319  *
320  */
321 EAPI void
322 ecore_timer_freeze(Ecore_Timer *timer)
323 {
324    double now;
325
326    if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER))
327      {
328         ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER,
329                          "ecore_timer_freeze");
330         return ;
331      }
332
333    /* Timer already frozen */
334    if (timer->frozen)
335      return ;
336
337    timers = (Ecore_Timer *) eina_inlist_remove(EINA_INLIST_GET(timers), EINA_INLIST_GET(timer));
338    suspended = (Ecore_Timer *) eina_inlist_prepend(EINA_INLIST_GET(suspended), EINA_INLIST_GET(timer));
339
340    now = ecore_time_get();
341
342    timer->pending = timer->at - now;
343    timer->at = 0.0;
344    timer->frozen = 1;
345 }
346
347 EAPI void
348 ecore_timer_thaw(Ecore_Timer *timer)
349 {
350    double now;
351
352    if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER))
353      {
354         ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER,
355                          "ecore_timer_thaw");
356         return ;
357      }
358
359    /* Timer not frozen */
360    if (!timer->frozen)
361      return ;
362
363    suspended = (Ecore_Timer *) eina_inlist_remove(EINA_INLIST_GET(suspended), EINA_INLIST_GET(timer));
364    now = ecore_time_get();
365
366    _ecore_timer_set(timer, timer->pending + now, timer->in, timer->func, timer->data);
367 }
368
369 EAPI char *
370 ecore_timer_dump(void)
371 {
372 #ifdef WANT_ECORE_TIMER_DUMP
373    Eina_Strbuf *result;
374    char *out;
375    Ecore_Timer *tm;
376    Eina_List *tmp = NULL;
377    int living_timer = 0;
378    int unknow_timer = 0;
379
380    result = eina_strbuf_new();
381
382    EINA_INLIST_FOREACH(timers, tm)
383      tmp = eina_list_sorted_insert(tmp, _ecore_timer_cmp, tm);
384
385    EINA_LIST_FREE(tmp, tm)
386      {
387         char **strings;
388         int j;
389
390         if (!tm->frozen && !tm->delete_me)
391           living_timer++;
392
393         strings = backtrace_symbols((void**) tm->timer_bt, tm->timer_bt_num);
394         if (tm->timer_bt_num <= 0 || strings == NULL)
395           {
396             unknow_timer++;
397             continue ;
398           }
399
400         eina_strbuf_append_printf(result, "*** timer: %f ***\n", tm->in);
401         if (tm->frozen)
402           eina_strbuf_append(result, "FROZEN\n");
403         if (tm->delete_me)
404           eina_strbuf_append(result, "DELETED\n");
405         for (j = 0; j < tm->timer_bt_num; j++)
406           eina_strbuf_append_printf(result, "%s\n", strings[j]);
407
408         free(strings);
409      }
410
411    eina_strbuf_append_printf(result, "\n***\nThere is %i living timer.\nWe did lost track of %i timers.\n", living_timer, unknow_timer);
412
413    out = eina_strbuf_string_steal(result);
414    eina_strbuf_free(result);
415
416    return out;
417 #else
418    return NULL;
419 #endif
420 }
421
422 /**
423  * @}
424  */
425
426 /**
427  * @}
428  */
429
430 void
431 _ecore_timer_shutdown(void)
432 {
433    Ecore_Timer *timer;
434
435    while ((timer = timers))
436      {
437         timers = (Ecore_Timer *) eina_inlist_remove(EINA_INLIST_GET(timers), EINA_INLIST_GET(timers));
438         ECORE_MAGIC_SET(timer, ECORE_MAGIC_NONE);
439         free(timer);
440      }
441
442    while ((timer = suspended))
443      {
444         suspended = (Ecore_Timer *) eina_inlist_remove(EINA_INLIST_GET(suspended), EINA_INLIST_GET(suspended));
445         ECORE_MAGIC_SET(timer, ECORE_MAGIC_NONE);
446         free(timer);
447      }
448
449    timer_current = NULL;
450 }
451
452 void
453 _ecore_timer_cleanup(void)
454 {
455    Ecore_Timer *l;
456    int in_use = 0, todo = timers_delete_me, done = 0;
457
458    if (!timers_delete_me) return;
459    for (l = timers; l;)
460      {
461         Ecore_Timer *timer = l;
462
463         l = (Ecore_Timer *) EINA_INLIST_GET(l)->next;
464         if (timer->delete_me)
465           {
466              if (timer->references)
467                {
468                   in_use++;
469                   continue;
470                }
471              timers = (Ecore_Timer *) eina_inlist_remove(EINA_INLIST_GET(timers), EINA_INLIST_GET(timer));
472              ECORE_MAGIC_SET(timer, ECORE_MAGIC_NONE);
473              free(timer);
474              timers_delete_me--;
475              done++;
476              if (timers_delete_me == 0) return;
477           }
478      }
479    for (l = suspended; l;)
480      {
481         Ecore_Timer *timer = l;
482
483         l = (Ecore_Timer *) EINA_INLIST_GET(l)->next;
484         if (timer->delete_me)
485           {
486              if (timer->references)
487                {
488                   in_use++;
489                   continue;
490                }
491              suspended = (Ecore_Timer *) eina_inlist_remove(EINA_INLIST_GET(suspended), EINA_INLIST_GET(timer));
492              ECORE_MAGIC_SET(timer, ECORE_MAGIC_NONE);
493              free(timer);
494              timers_delete_me--;
495              done++;
496              if (timers_delete_me == 0) return;
497           }
498      }
499
500    if ((!in_use) && (timers_delete_me))
501      {
502         ERR("%d timers to delete, but they were not found!"
503             "Stats: todo=%d, done=%d, pending=%d, in_use=%d. "
504             "reset counter.",
505             timers_delete_me, todo, done, todo - done, in_use);
506         timers_delete_me = 0;
507      }
508 }
509
510 void
511 _ecore_timer_enable_new(void)
512 {
513    Ecore_Timer *timer;
514
515    if (!timers_added) return;
516    timers_added = 0;
517    EINA_INLIST_FOREACH(timers, timer) timer->just_added = 0;
518 }
519
520 int
521 _ecore_timers_exists(void)
522 {
523    Ecore_Timer *timer = timers;
524
525    while ((timer) && (timer->delete_me))
526      timer = (Ecore_Timer *)EINA_INLIST_GET(timer)->next;
527
528    return !!timer;
529 }
530
531 static inline Ecore_Timer *
532 _ecore_timer_first_get(void)
533 {
534    Ecore_Timer *timer = timers;
535
536    while ((timer) && ((timer->delete_me) || (timer->just_added)))
537      timer = (Ecore_Timer *) EINA_INLIST_GET(timer)->next;
538
539    return timer;
540 }
541
542 static inline Ecore_Timer *
543 _ecore_timer_after_get(Ecore_Timer *base)
544 {
545    Ecore_Timer *timer = (Ecore_Timer *) EINA_INLIST_GET(base)->next;
546    double maxtime = base->at + precision;
547
548    while ((timer) && ((timer->delete_me) || (timer->just_added)) && (timer->at <= maxtime))
549      timer = (Ecore_Timer *) EINA_INLIST_GET(timer)->next;
550
551    if ((!timer) || (timer->at > maxtime))
552      return NULL;
553
554    return timer;
555 }
556
557 double
558 _ecore_timer_next_get(void)
559 {
560    double now;
561    double in;
562    Ecore_Timer *first, *second;
563
564    first = _ecore_timer_first_get();
565    if (!first) return -1;
566
567    second = _ecore_timer_after_get(first);
568    if (second)
569      first = second;
570
571    now = ecore_loop_time_get();
572    in = first->at - now;
573    if (in < 0) in = 0;
574    return in;
575 }
576
577 static inline void
578 _ecore_timer_reschedule(Ecore_Timer *timer, double when)
579 {
580    if ((timer->delete_me) || (timer->frozen)) return;
581
582    timers = (Ecore_Timer *) eina_inlist_remove(EINA_INLIST_GET(timers), EINA_INLIST_GET(timer));
583
584    /* if the timer would have gone off more than 15 seconds ago,
585     * assume that the system hung and set the timer to go off
586     * timer->in from now. this handles system hangs, suspends
587     * and more, so ecore will only "replay" the timers while
588     * the system is suspended if it is suspended for less than
589     * 15 seconds (basically). this also handles if the process
590     * is stopped in a debugger or IO and other handling gets
591     * really slow within the main loop.
592     */
593    if ((timer->at + timer->in) < (when - 15.0))
594      _ecore_timer_set(timer, when + timer->in, timer->in, timer->func, timer->data);
595    else
596      _ecore_timer_set(timer, timer->at + timer->in, timer->in, timer->func, timer->data);
597 }
598
599 int
600 _ecore_timer_call(double when)
601 {
602    if (!timers) return 0;
603    if (last_check > when)
604      {
605         Ecore_Timer *timer;
606         /* User set time backwards */
607         EINA_INLIST_FOREACH(timers, timer) timer->at -= (last_check - when);
608      }
609    last_check = when;
610
611    if (!timer_current)
612      {
613         /* regular main loop, start from head */
614         timer_current = timers;
615      }
616    else
617      {
618         /* recursive main loop, continue from where we were */
619         Ecore_Timer *timer_old = timer_current;
620         timer_current = (Ecore_Timer *)EINA_INLIST_GET(timer_current)->next;
621         _ecore_timer_reschedule(timer_old, when);
622      }
623
624    while (timer_current)
625      {
626         Ecore_Timer *timer = timer_current;
627
628         if (timer->at > when)
629           {
630              timer_current = NULL; /* ended walk, next should restart. */
631              return 0;
632           }
633
634         if ((timer->just_added) || (timer->delete_me))
635           {
636              timer_current = (Ecore_Timer*)EINA_INLIST_GET(timer_current)->next;
637              continue;
638           }
639
640         timer->references++;
641         if (!timer->func(timer->data))
642           {
643              if (!timer->delete_me) ecore_timer_del(timer);
644           }
645         timer->references--;
646
647         if (timer_current) /* may have changed in recursive main loops */
648           timer_current = (Ecore_Timer *)EINA_INLIST_GET(timer_current)->next;
649
650         _ecore_timer_reschedule(timer, when);
651      }
652    return 0;
653 }
654
655 static void
656 _ecore_timer_set(Ecore_Timer *timer, double at, double in, Ecore_Task_Cb func, void *data)
657 {
658    Ecore_Timer *t2;
659
660    timers_added = 1;
661    timer->at = at;
662    timer->in = in;
663    timer->func = func;
664    timer->data = data;
665    timer->just_added = 1;
666    timer->frozen = 0;
667    timer->pending = 0.0;
668    if (timers)
669      {
670         EINA_INLIST_REVERSE_FOREACH(EINA_INLIST_GET(timers), t2)
671           {
672              if (timer->at > t2->at)
673                {
674                   timers = (Ecore_Timer *) eina_inlist_append_relative(EINA_INLIST_GET(timers), EINA_INLIST_GET(timer), EINA_INLIST_GET(t2));
675                   return;
676                }
677           }
678      }
679    timers = (Ecore_Timer *) eina_inlist_prepend(EINA_INLIST_GET(timers), EINA_INLIST_GET(timer));
680 }
681
682 static int
683 _ecore_timer_cmp(const void *d1, const void *d2)
684 {
685    const Ecore_Timer *t1 = d1;
686    const Ecore_Timer *t2 = d2;
687
688    return (int) ((t1->in - t2->in) * 100);
689 }