9 #include "ecore_private.h"
11 #ifdef WANT_ECORE_TIMER_DUMP
13 # include <execinfo.h>
14 # define ECORE_TIMER_DEBUG_BT_NUM 64
15 typedef void (*Ecore_Timer_Bt_Func) ();
28 #ifdef WANT_ECORE_TIMER_DUMP
29 Ecore_Timer_Bt_Func timer_bt[ECORE_TIMER_DEBUG_BT_NUM];
34 unsigned char delete_me : 1;
35 unsigned char just_added : 1;
36 unsigned char frozen : 1;
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);
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;
52 * @addtogroup Ecore_Group Ecore - Main Loop and Job Functions.
58 * @addtogroup Ecore_Time_Group Ecore Time functions
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.
63 * The timer allows callbacks to be called at specific intervals.
69 * Retrieves the current precision used by timer infrastructure.
71 * @see ecore_timer_precision_set()
74 ecore_timer_precision_get(void)
80 * Sets the precision to be used by timer infrastructure.
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
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.
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.
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.
101 * @param value allowed introduced timeout delay, in seconds.
104 ecore_timer_precision_set(double value)
108 ERR("Precision %f less than zero, ignored", value);
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.
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.
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
133 ecore_timer_add(double in, Ecore_Task_Cb func, const void *data)
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();
145 #ifdef WANT_ECORE_TIMER_DUMP
146 timer->timer_bt_num = backtrace((void**) (timer->timer_bt),
147 ECORE_TIMER_DEBUG_BT_NUM);
150 _ecore_timer_set(timer, now + in, in, func, (void *)data);
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.
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.
167 ecore_timer_loop_add(double in, Ecore_Task_Cb func, const void *data)
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();
179 #ifdef WANT_ECORE_TIMER_DUMP
180 timer->timer_bt_num = backtrace((void**) (timer->timer_bt),
181 ECORE_TIMER_DEBUG_BT_NUM);
184 _ecore_timer_set(timer, now + in, in, func, (void *)data);
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.
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).
198 ecore_timer_del(Ecore_Timer *timer)
200 if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER))
202 ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER,
207 if (timer->frozen && !timer->references)
209 void *data = timer->data;
211 suspended = (Ecore_Timer *) eina_inlist_remove(EINA_INLIST_GET(suspended), EINA_INLIST_GET(timer));
213 if (timer->delete_me)
220 EINA_SAFETY_ON_TRUE_RETURN_VAL(timer->delete_me, NULL);
221 timer->delete_me = 1;
227 * Change the interval the timer ticks of. If set during
228 * a timer call, this will affect the next interval.
230 * @param timer The timer to change.
231 * @param in The interval in seconds.
234 ecore_timer_interval_set(Ecore_Timer *timer, double in)
236 if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER))
238 ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER,
239 "ecore_timer_interval_set");
246 * Get the interval the timer ticks on.
248 * @param timer The timer to retrieve the interval from
249 * @return The interval on success. -1 on failure.
252 ecore_timer_interval_get(Ecore_Timer *timer)
254 if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER))
256 ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER,
257 "ecore_timer_interval_get");
265 * Add some delay for the next occurrence of a timer.
266 * This doesn't affect the interval of a timer.
268 * @param timer The timer to change.
269 * @param add The dalay to add to the next iteration.
272 ecore_timer_delay(Ecore_Timer *timer, double add)
274 if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER))
276 ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER,
277 "ecore_timer_delay");
283 timer->pending += add;
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);
293 * Get the pending time regarding a timer.
295 * @param timer The timer to learn from.
296 * @ingroup Ecore_Time_Group
299 ecore_timer_pending_get(Ecore_Timer *timer)
303 if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER))
305 ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER,
306 "ecore_timer_pending_get");
310 now = ecore_time_get();
313 return timer->pending;
314 return timer->at - now;
322 ecore_timer_freeze(Ecore_Timer *timer)
326 if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER))
328 ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER,
329 "ecore_timer_freeze");
333 /* Timer already frozen */
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));
340 now = ecore_time_get();
342 timer->pending = timer->at - now;
348 ecore_timer_thaw(Ecore_Timer *timer)
352 if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER))
354 ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER,
359 /* Timer not frozen */
363 suspended = (Ecore_Timer *) eina_inlist_remove(EINA_INLIST_GET(suspended), EINA_INLIST_GET(timer));
364 now = ecore_time_get();
366 _ecore_timer_set(timer, timer->pending + now, timer->in, timer->func, timer->data);
370 ecore_timer_dump(void)
372 #ifdef WANT_ECORE_TIMER_DUMP
376 Eina_List *tmp = NULL;
377 int living_timer = 0;
378 int unknow_timer = 0;
380 result = eina_strbuf_new();
382 EINA_INLIST_FOREACH(timers, tm)
383 tmp = eina_list_sorted_insert(tmp, _ecore_timer_cmp, tm);
385 EINA_LIST_FREE(tmp, tm)
390 if (!tm->frozen && !tm->delete_me)
393 strings = backtrace_symbols((void**) tm->timer_bt, tm->timer_bt_num);
394 if (tm->timer_bt_num <= 0 || strings == NULL)
400 eina_strbuf_append_printf(result, "*** timer: %f ***\n", tm->in);
402 eina_strbuf_append(result, "FROZEN\n");
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]);
411 eina_strbuf_append_printf(result, "\n***\nThere is %i living timer.\nWe did lost track of %i timers.\n", living_timer, unknow_timer);
413 out = eina_strbuf_string_steal(result);
414 eina_strbuf_free(result);
431 _ecore_timer_shutdown(void)
435 while ((timer = timers))
437 timers = (Ecore_Timer *) eina_inlist_remove(EINA_INLIST_GET(timers), EINA_INLIST_GET(timers));
438 ECORE_MAGIC_SET(timer, ECORE_MAGIC_NONE);
442 while ((timer = suspended))
444 suspended = (Ecore_Timer *) eina_inlist_remove(EINA_INLIST_GET(suspended), EINA_INLIST_GET(suspended));
445 ECORE_MAGIC_SET(timer, ECORE_MAGIC_NONE);
449 timer_current = NULL;
453 _ecore_timer_cleanup(void)
456 int in_use = 0, todo = timers_delete_me, done = 0;
458 if (!timers_delete_me) return;
461 Ecore_Timer *timer = l;
463 l = (Ecore_Timer *) EINA_INLIST_GET(l)->next;
464 if (timer->delete_me)
466 if (timer->references)
471 timers = (Ecore_Timer *) eina_inlist_remove(EINA_INLIST_GET(timers), EINA_INLIST_GET(timer));
472 ECORE_MAGIC_SET(timer, ECORE_MAGIC_NONE);
476 if (timers_delete_me == 0) return;
479 for (l = suspended; l;)
481 Ecore_Timer *timer = l;
483 l = (Ecore_Timer *) EINA_INLIST_GET(l)->next;
484 if (timer->delete_me)
486 if (timer->references)
491 suspended = (Ecore_Timer *) eina_inlist_remove(EINA_INLIST_GET(suspended), EINA_INLIST_GET(timer));
492 ECORE_MAGIC_SET(timer, ECORE_MAGIC_NONE);
496 if (timers_delete_me == 0) return;
500 if ((!in_use) && (timers_delete_me))
502 ERR("%d timers to delete, but they were not found!"
503 "Stats: todo=%d, done=%d, pending=%d, in_use=%d. "
505 timers_delete_me, todo, done, todo - done, in_use);
506 timers_delete_me = 0;
511 _ecore_timer_enable_new(void)
515 if (!timers_added) return;
517 EINA_INLIST_FOREACH(timers, timer) timer->just_added = 0;
521 _ecore_timers_exists(void)
523 Ecore_Timer *timer = timers;
525 while ((timer) && (timer->delete_me))
526 timer = (Ecore_Timer *)EINA_INLIST_GET(timer)->next;
531 static inline Ecore_Timer *
532 _ecore_timer_first_get(void)
534 Ecore_Timer *timer = timers;
536 while ((timer) && ((timer->delete_me) || (timer->just_added)))
537 timer = (Ecore_Timer *) EINA_INLIST_GET(timer)->next;
542 static inline Ecore_Timer *
543 _ecore_timer_after_get(Ecore_Timer *base)
545 Ecore_Timer *timer = (Ecore_Timer *) EINA_INLIST_GET(base)->next;
546 double maxtime = base->at + precision;
548 while ((timer) && ((timer->delete_me) || (timer->just_added)) && (timer->at <= maxtime))
549 timer = (Ecore_Timer *) EINA_INLIST_GET(timer)->next;
551 if ((!timer) || (timer->at > maxtime))
558 _ecore_timer_next_get(void)
562 Ecore_Timer *first, *second;
564 first = _ecore_timer_first_get();
565 if (!first) return -1;
567 second = _ecore_timer_after_get(first);
571 now = ecore_loop_time_get();
572 in = first->at - now;
578 _ecore_timer_reschedule(Ecore_Timer *timer, double when)
580 if ((timer->delete_me) || (timer->frozen)) return;
582 timers = (Ecore_Timer *) eina_inlist_remove(EINA_INLIST_GET(timers), EINA_INLIST_GET(timer));
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.
593 if ((timer->at + timer->in) < (when - 15.0))
594 _ecore_timer_set(timer, when + timer->in, timer->in, timer->func, timer->data);
596 _ecore_timer_set(timer, timer->at + timer->in, timer->in, timer->func, timer->data);
600 _ecore_timer_call(double when)
602 if (!timers) return 0;
603 if (last_check > when)
606 /* User set time backwards */
607 EINA_INLIST_FOREACH(timers, timer) timer->at -= (last_check - when);
613 /* regular main loop, start from head */
614 timer_current = timers;
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);
624 while (timer_current)
626 Ecore_Timer *timer = timer_current;
628 if (timer->at > when)
630 timer_current = NULL; /* ended walk, next should restart. */
634 if ((timer->just_added) || (timer->delete_me))
636 timer_current = (Ecore_Timer*)EINA_INLIST_GET(timer_current)->next;
641 if (!timer->func(timer->data))
643 if (!timer->delete_me) ecore_timer_del(timer);
647 if (timer_current) /* may have changed in recursive main loops */
648 timer_current = (Ecore_Timer *)EINA_INLIST_GET(timer_current)->next;
650 _ecore_timer_reschedule(timer, when);
656 _ecore_timer_set(Ecore_Timer *timer, double at, double in, Ecore_Task_Cb func, void *data)
665 timer->just_added = 1;
667 timer->pending = 0.0;
670 EINA_INLIST_REVERSE_FOREACH(EINA_INLIST_GET(timers), t2)
672 if (timer->at > t2->at)
674 timers = (Ecore_Timer *) eina_inlist_append_relative(EINA_INLIST_GET(timers), EINA_INLIST_GET(timer), EINA_INLIST_GET(t2));
679 timers = (Ecore_Timer *) eina_inlist_prepend(EINA_INLIST_GET(timers), EINA_INLIST_GET(timer));
683 _ecore_timer_cmp(const void *d1, const void *d2)
685 const Ecore_Timer *t1 = d1;
686 const Ecore_Timer *t2 = d2;
688 return (int) ((t1->in - t2->in) * 100);