[ecore] merged svn latest code (svn54830)
[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
12 struct _Ecore_Timer
13 {
14    EINA_INLIST;
15    ECORE_MAGIC;
16    double          in;
17    double          at;
18    double          pending;
19    Ecore_Task_Cb   func;
20    void           *data;
21
22    int             references;
23    unsigned char   delete_me : 1;
24    unsigned char   just_added : 1;
25    unsigned char   frozen : 1;
26 };
27
28
29 static void _ecore_timer_set(Ecore_Timer *timer, double at, double in, Ecore_Task_Cb func, void *data);
30
31 static int          timers_added = 0;
32 static int          timers_delete_me = 0;
33 static Ecore_Timer *timers = NULL;
34 static Ecore_Timer *timer_current = NULL;
35 static Ecore_Timer *suspended = NULL;
36 static double       last_check = 0.0;
37 static double       precision = 10.0 / 1000000.0;
38
39 /**
40  * @addtogroup Ecore_Group Ecore - Main Loop and Job Functions.
41  *
42  * @{
43  */
44
45 /**
46  * @addtogroup Ecore_Time_Group Ecore Time functions
47  *
48  * Functions that deal with time.  These functions include those that simply
49  * retrieve it in a given format, and those that create events based on it.
50  *
51  * The timer allows callbacks to be called at specific intervals.
52  *
53  * @{
54  */
55
56 /**
57  * Retrieves the current precision used by timer infrastructure.
58  *
59  * @see ecore_timer_precision_set()
60  */
61 EAPI double
62 ecore_timer_precision_get(void)
63 {
64    return precision;
65 }
66
67 /**
68  * Sets the precision to be used by timer infrastructure.
69  *
70  * When system calculates time to expire the next timer we'll be able
71  * to delay the timer by the given amount so more timers will fit in
72  * the same dispatch, waking up the system less often and thus being
73  * able to save power.
74  *
75  * Be aware that kernel may delay delivery even further, these delays
76  * are always possible due other tasks having higher priorities or
77  * other scheduler policies.
78  *
79  * Example:
80  *  We have 2 timers, one that expires in a 2.0s and another that
81  *  expires in 2.1s, if precision is 0.1s, then the Ecore will request
82  *  for the next expire to happen in 2.1s and not 2.0s and another one
83  *  of 0.1 as it would before.
84  *
85  * @note Ecore is smart enough to see if there are timers in the
86  * precision range, if it does not, in our example if no second timer
87  * in (T + precision) existed, then it would use the minimum timeout.
88  *
89  * @param value allowed introduced timeout delay, in seconds.
90  */
91 EAPI void
92 ecore_timer_precision_set(double value)
93 {
94    if (value < 0.0)
95      {
96         ERR("Precision %f less than zero, ignored", value);
97         return;
98      }
99    precision = value;
100 }
101
102 /**
103  * Creates a timer to call the given function in the given period of time.
104  * @param   in   The interval in seconds.
105  * @param   func The given function.  If @p func returns 1, the timer is
106  *               rescheduled for the next interval @p in.
107  * @param   data Data to pass to @p func when it is called.
108  * @return  A timer object on success.  @c NULL on failure.
109  *
110  * This function adds a timer and returns its handle on success and NULL on
111  * failure. The function @p func will be called every @p in seconds. The
112  * function will be passed the @p data pointer as its parameter.
113  *
114  * When the timer @p func is called, it must return a value of either 1
115  * (or ECORE_CALLBACK_RENEW) or 0 (or ECORE_CALLBACK_CANCEL).
116  * If it returns 1, it will be called again at the next tick, or if it returns
117  * 0 it will be deleted automatically making any references/handles for it
118  * invalid.
119  */
120 EAPI Ecore_Timer *
121 ecore_timer_add(double in, Ecore_Task_Cb func, const void *data)
122 {
123    double now;
124    Ecore_Timer *timer;
125
126    if (!func) return NULL;
127    if (in < 0.0) in = 0.0;
128    timer = calloc(1, sizeof(Ecore_Timer));
129    if (!timer) return NULL;
130    ECORE_MAGIC_SET(timer, ECORE_MAGIC_TIMER);
131    now = ecore_time_get();
132    _ecore_timer_set(timer, now + in, in, func, (void *)data);
133    return timer;
134 }
135
136 /**
137  * Creates a timer to call the given function in the given period of time.
138  * @param   in   The interval in seconds from current loop time.
139  * @param   func The given function.  If @p func returns 1, the timer is
140  *               rescheduled for the next interval @p in.
141  * @param   data Data to pass to @p func when it is called.
142  * @return  A timer object on success.  @c NULL on failure.
143  *
144  * This is the same as ecore_timer_add(), but "now" is the time from
145  * ecore_loop_time_get() not ecore_time_get() as ecore_timer_add() uses. See
146  * ecore_timer_add() for more details.
147  */
148 EAPI Ecore_Timer *
149 ecore_timer_loop_add(double in, Ecore_Task_Cb func, const void *data)
150 {
151    double now;
152    Ecore_Timer *timer;
153
154    if (!func) return NULL;
155    if (in < 0.0) in = 0.0;
156    timer = calloc(1, sizeof(Ecore_Timer));
157    if (!timer) return NULL;
158    ECORE_MAGIC_SET(timer, ECORE_MAGIC_TIMER);
159    now = ecore_loop_time_get();
160    _ecore_timer_set(timer, now + in, in, func, (void *)data);
161    return timer;
162 }
163
164 /**
165  * Delete the specified timer from the timer list.
166  * @param   timer The timer to delete.
167  * @return  The data pointer set for the timer when @ref ecore_timer_add was
168  *          called.  @c NULL is returned if the function is unsuccessful.
169  *
170  * Note: @p timer must be a valid handle. If the timer function has already
171  * returned 0, the handle is no longer valid (and does not need to be delete).
172  */
173 EAPI void *
174 ecore_timer_del(Ecore_Timer *timer)
175 {
176    if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER))
177      {
178         ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER,
179                          "ecore_timer_del");
180         return NULL;
181      }
182
183    if (timer->frozen && !timer->references)
184      {
185         void *data = timer->data;
186
187         suspended = (Ecore_Timer *) eina_inlist_remove(EINA_INLIST_GET(suspended), EINA_INLIST_GET(timer));
188
189         if (timer->delete_me)
190           timers_delete_me--;
191
192         free(timer);
193         return data;
194      }
195
196    EINA_SAFETY_ON_TRUE_RETURN_VAL(timer->delete_me, NULL);
197    timer->delete_me = 1;
198    timers_delete_me++;
199    return timer->data;
200 }
201
202 /**
203  * Change the interval the timer ticks of. If set during
204  * a timer call, this will affect the next interval.
205  *
206  * @param   timer The timer to change.
207  * @param   in    The interval in seconds.
208  */
209 EAPI void
210 ecore_timer_interval_set(Ecore_Timer *timer, double in)
211 {
212    if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER))
213      {
214         ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER,
215                          "ecore_timer_interval_set");
216         return;
217      }
218    timer->in = in;
219 }
220
221 /**
222  * Get the interval the timer ticks on.
223  *
224  * @param   timer The timer to retrieve the interval from
225  * @return  The interval on success. -1 on failure.
226  */
227 EAPI double
228 ecore_timer_interval_get(Ecore_Timer *timer)
229 {
230    if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER))
231      {
232         ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER,
233                          "ecore_timer_interval_get");
234         return -1.0;
235      }
236
237    return timer->in;
238 }
239
240 /**
241  * Add some delay for the next occurrence of a timer.
242  * This doesn't affect the interval of a timer.
243  *
244  * @param   timer The timer to change.
245  * @param   add   The dalay to add to the next iteration.
246  */
247 EAPI void
248 ecore_timer_delay(Ecore_Timer *timer, double add)
249 {
250    if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER))
251      {
252         ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER,
253                          "ecore_timer_delay");
254         return;
255      }
256
257    if (timer->frozen)
258      {
259         timer->pending += add;
260      }
261    else
262      {
263         timers = (Ecore_Timer *) eina_inlist_remove(EINA_INLIST_GET(timers), EINA_INLIST_GET(timer));
264         _ecore_timer_set(timer, timer->at + add, timer->in, timer->func, timer->data);
265      }
266 }
267
268 /**
269  * Get the pending time regarding a timer.
270  *
271  * @param        timer The timer to learn from.
272  * @ingroup        Ecore_Time_Group
273  */
274 EAPI double
275 ecore_timer_pending_get(Ecore_Timer *timer)
276 {
277    double        now;
278
279    if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER))
280      {
281         ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER,
282                          "ecore_timer_pending_get");
283         return 0;
284      }
285
286    now = ecore_time_get();
287
288    if (timer->frozen)
289      return timer->pending;
290    return timer->at - now;
291 }
292
293 /**
294  *
295  *
296  */
297 EAPI void
298 ecore_timer_freeze(Ecore_Timer *timer)
299 {
300    double now;
301
302    if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER))
303      {
304         ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER,
305                          "ecore_timer_freeze");
306         return ;
307      }
308
309    /* Timer already frozen */
310    if (timer->frozen)
311      return ;
312
313    timers = (Ecore_Timer *) eina_inlist_remove(EINA_INLIST_GET(timers), EINA_INLIST_GET(timer));
314    suspended = (Ecore_Timer *) eina_inlist_prepend(EINA_INLIST_GET(suspended), EINA_INLIST_GET(timer));
315
316    now = ecore_time_get();
317
318    timer->pending = timer->at - now;
319    timer->at = 0.0;
320    timer->frozen = 1;
321 }
322
323 EAPI void
324 ecore_timer_thaw(Ecore_Timer *timer)
325 {
326    double now;
327
328    if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER))
329      {
330         ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER,
331                          "ecore_timer_thaw");
332         return ;
333      }
334
335    /* Timer not frozen */
336    if (!timer->frozen)
337      return ;
338
339    suspended = (Ecore_Timer *) eina_inlist_remove(EINA_INLIST_GET(suspended), EINA_INLIST_GET(timer));
340    now = ecore_time_get();
341
342    _ecore_timer_set(timer, timer->pending + now, timer->in, timer->func, timer->data);
343 }
344
345 /**
346  * @}
347  */
348
349 /**
350  * @}
351  */
352
353 void
354 _ecore_timer_shutdown(void)
355 {
356    Ecore_Timer *timer;
357
358    while ((timer = timers))
359      {
360         timers = (Ecore_Timer *) eina_inlist_remove(EINA_INLIST_GET(timers), EINA_INLIST_GET(timers));
361         ECORE_MAGIC_SET(timer, ECORE_MAGIC_NONE);
362         free(timer);
363      }
364
365    while ((timer = suspended))
366      {
367         suspended = (Ecore_Timer *) eina_inlist_remove(EINA_INLIST_GET(suspended), EINA_INLIST_GET(suspended));
368         ECORE_MAGIC_SET(timer, ECORE_MAGIC_NONE);
369         free(timer);
370      }
371
372    timer_current = NULL;
373 }
374
375 void
376 _ecore_timer_cleanup(void)
377 {
378    Ecore_Timer *l;
379    int in_use = 0, todo = timers_delete_me, done = 0;
380
381    if (!timers_delete_me) return;
382    for (l = timers; l;)
383      {
384         Ecore_Timer *timer = l;
385
386         l = (Ecore_Timer *) EINA_INLIST_GET(l)->next;
387         if (timer->delete_me)
388           {
389              if (timer->references)
390                {
391                   in_use++;
392                   continue;
393                }
394              timers = (Ecore_Timer *) eina_inlist_remove(EINA_INLIST_GET(timers), EINA_INLIST_GET(timer));
395              ECORE_MAGIC_SET(timer, ECORE_MAGIC_NONE);
396              free(timer);
397              timers_delete_me--;
398              done++;
399              if (timers_delete_me == 0) return;
400           }
401      }
402    for (l = suspended; l;)
403      {
404         Ecore_Timer *timer = l;
405
406         l = (Ecore_Timer *) EINA_INLIST_GET(l)->next;
407         if (timer->delete_me)
408           {
409              if (timer->references)
410                {
411                   in_use++;
412                   continue;
413                }
414              suspended = (Ecore_Timer *) eina_inlist_remove(EINA_INLIST_GET(suspended), EINA_INLIST_GET(timer));
415              ECORE_MAGIC_SET(timer, ECORE_MAGIC_NONE);
416              free(timer);
417              timers_delete_me--;
418              done++;
419              if (timers_delete_me == 0) return;
420           }
421      }
422
423    if ((!in_use) && (timers_delete_me))
424      {
425         ERR("%d timers to delete, but they were not found!"
426             "Stats: todo=%d, done=%d, pending=%d, in_use=%d. "
427             "reset counter.",
428             timers_delete_me, todo, done, todo - done, in_use);
429         timers_delete_me = 0;
430      }
431 }
432
433 void
434 _ecore_timer_enable_new(void)
435 {
436    Ecore_Timer *timer;
437
438    if (!timers_added) return;
439    timers_added = 0;
440    EINA_INLIST_FOREACH(timers, timer) timer->just_added = 0;
441 }
442
443 int
444 _ecore_timers_exists(void)
445 {
446    Ecore_Timer *timer = timers;
447
448    while ((timer) && (timer->delete_me))
449      timer = (Ecore_Timer *)EINA_INLIST_GET(timer)->next;
450
451    return !!timer;
452 }
453
454 static inline Ecore_Timer *
455 _ecore_timer_first_get(void)
456 {
457    Ecore_Timer *timer = timers;
458
459    while ((timer) && ((timer->delete_me) || (timer->just_added)))
460      timer = (Ecore_Timer *) EINA_INLIST_GET(timer)->next;
461
462    return timer;
463 }
464
465 static inline Ecore_Timer *
466 _ecore_timer_after_get(Ecore_Timer *base)
467 {
468    Ecore_Timer *timer = (Ecore_Timer *) EINA_INLIST_GET(base)->next;
469    double maxtime = base->at + precision;
470
471    while ((timer) && ((timer->delete_me) || (timer->just_added)) && (timer->at <= maxtime))
472      timer = (Ecore_Timer *) EINA_INLIST_GET(timer)->next;
473
474    if ((!timer) || (timer->at > maxtime))
475      return NULL;
476
477    return timer;
478 }
479
480 double
481 _ecore_timer_next_get(void)
482 {
483    double now;
484    double in;
485    Ecore_Timer *first, *second;
486
487    first = _ecore_timer_first_get();
488    if (!first) return -1;
489
490    second = _ecore_timer_after_get(first);
491    if (second)
492      first = second;
493
494    now = ecore_loop_time_get();
495    in = first->at - now;
496    if (in < 0) in = 0;
497    return in;
498 }
499
500 static inline void
501 _ecore_timer_reschedule(Ecore_Timer *timer, double when)
502 {
503    if ((timer->delete_me) || (timer->frozen)) return;
504
505    timers = (Ecore_Timer *) eina_inlist_remove(EINA_INLIST_GET(timers), EINA_INLIST_GET(timer));
506
507    /* if the timer would have gone off more than 15 seconds ago,
508     * assume that the system hung and set the timer to go off
509     * timer->in from now. this handles system hangs, suspends
510     * and more, so ecore will only "replay" the timers while
511     * the system is suspended if it is suspended for less than
512     * 15 seconds (basically). this also handles if the process
513     * is stopped in a debugger or IO and other handling gets
514     * really slow within the main loop.
515     */
516    if ((timer->at + timer->in) < (when - 15.0))
517      _ecore_timer_set(timer, when + timer->in, timer->in, timer->func, timer->data);
518    else
519      _ecore_timer_set(timer, timer->at + timer->in, timer->in, timer->func, timer->data);
520 }
521
522 int
523 _ecore_timer_call(double when)
524 {
525    if (!timers) return 0;
526    if (last_check > when)
527      {
528         Ecore_Timer *timer;
529         /* User set time backwards */
530         EINA_INLIST_FOREACH(timers, timer) timer->at -= (last_check - when);
531      }
532    last_check = when;
533
534    if (!timer_current)
535      {
536         /* regular main loop, start from head */
537         timer_current = timers;
538      }
539    else
540      {
541         /* recursive main loop, continue from where we were */
542         Ecore_Timer *timer_old = timer_current;
543         timer_current = (Ecore_Timer *)EINA_INLIST_GET(timer_current)->next;
544         _ecore_timer_reschedule(timer_old, when);
545      }
546
547    while (timer_current)
548      {
549         Ecore_Timer *timer = timer_current;
550
551         if (timer->at > when)
552           {
553              timer_current = NULL; /* ended walk, next should restart. */
554              return 0;
555           }
556
557         if ((timer->just_added) || (timer->delete_me))
558           {
559              timer_current = (Ecore_Timer*)EINA_INLIST_GET(timer_current)->next;
560              continue;
561           }
562
563         timer->references++;
564         if (!timer->func(timer->data))
565           {
566              if (!timer->delete_me) ecore_timer_del(timer);
567           }
568         timer->references--;
569
570         if (timer_current) /* may have changed in recursive main loops */
571           timer_current = (Ecore_Timer *)EINA_INLIST_GET(timer_current)->next;
572
573         _ecore_timer_reschedule(timer, when);
574      }
575    return 0;
576 }
577
578 static void
579 _ecore_timer_set(Ecore_Timer *timer, double at, double in, Ecore_Task_Cb func, void *data)
580 {
581    Ecore_Timer *t2;
582
583    timers_added = 1;
584    timer->at = at;
585    timer->in = in;
586    timer->func = func;
587    timer->data = data;
588    timer->just_added = 1;
589    timer->frozen = 0;
590    timer->pending = 0.0;
591    if (timers)
592      {
593         EINA_INLIST_REVERSE_FOREACH(EINA_INLIST_GET(timers), t2)
594           {
595              if (timer->at > t2->at)
596                {
597                   timers = (Ecore_Timer *) eina_inlist_append_relative(EINA_INLIST_GET(timers), EINA_INLIST_GET(timer), EINA_INLIST_GET(t2));
598                   return;
599                }
600           }
601      }
602    timers = (Ecore_Timer *) eina_inlist_prepend(EINA_INLIST_GET(timers), EINA_INLIST_GET(timer));
603 }