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