9 #include "ecore_private.h"
23 unsigned char delete_me : 1;
24 unsigned char just_added : 1;
25 unsigned char frozen : 1;
29 static void _ecore_timer_set(Ecore_Timer *timer, double at, double in, Ecore_Task_Cb func, void *data);
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;
40 * @addtogroup Ecore_Group Ecore - Main Loop and Job Functions.
46 * @addtogroup Ecore_Time_Group Ecore Time functions
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.
51 * The timer allows callbacks to be called at specific intervals.
57 * Retrieves the current precision used by timer infrastructure.
59 * @see ecore_timer_precision_set()
62 ecore_timer_precision_get(void)
68 * Sets the precision to be used by timer infrastructure.
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
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.
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.
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.
89 * @param value allowed introduced timeout delay, in seconds.
92 ecore_timer_precision_set(double value)
96 ERR("Precision %f less than zero, ignored", value);
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.
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.
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
121 ecore_timer_add(double in, Ecore_Task_Cb func, const void *data)
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);
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.
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.
149 ecore_timer_loop_add(double in, Ecore_Task_Cb func, const void *data)
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);
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.
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).
174 ecore_timer_del(Ecore_Timer *timer)
176 if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER))
178 ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER,
183 if (timer->frozen && !timer->references)
185 void *data = timer->data;
187 suspended = (Ecore_Timer *) eina_inlist_remove(EINA_INLIST_GET(suspended), EINA_INLIST_GET(timer));
189 if (timer->delete_me)
196 EINA_SAFETY_ON_TRUE_RETURN_VAL(timer->delete_me, NULL);
197 timer->delete_me = 1;
203 * Change the interval the timer ticks of. If set during
204 * a timer call, this will affect the next interval.
206 * @param timer The timer to change.
207 * @param in The interval in seconds.
210 ecore_timer_interval_set(Ecore_Timer *timer, double in)
212 if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER))
214 ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER,
215 "ecore_timer_interval_set");
222 * Get the interval the timer ticks on.
224 * @param timer The timer to retrieve the interval from
225 * @return The interval on success. -1 on failure.
228 ecore_timer_interval_get(Ecore_Timer *timer)
230 if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER))
232 ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER,
233 "ecore_timer_interval_get");
241 * Add some delay for the next occurrence of a timer.
242 * This doesn't affect the interval of a timer.
244 * @param timer The timer to change.
245 * @param add The dalay to add to the next iteration.
248 ecore_timer_delay(Ecore_Timer *timer, double add)
250 if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER))
252 ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER,
253 "ecore_timer_delay");
259 timer->pending += add;
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);
269 * Get the pending time regarding a timer.
271 * @param timer The timer to learn from.
272 * @ingroup Ecore_Time_Group
275 ecore_timer_pending_get(Ecore_Timer *timer)
279 if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER))
281 ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER,
282 "ecore_timer_pending_get");
286 now = ecore_time_get();
289 return timer->pending;
290 return timer->at - now;
298 ecore_timer_freeze(Ecore_Timer *timer)
302 if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER))
304 ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER,
305 "ecore_timer_freeze");
309 /* Timer already frozen */
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));
316 now = ecore_time_get();
318 timer->pending = timer->at - now;
324 ecore_timer_thaw(Ecore_Timer *timer)
328 if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER))
330 ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER,
335 /* Timer not frozen */
339 suspended = (Ecore_Timer *) eina_inlist_remove(EINA_INLIST_GET(suspended), EINA_INLIST_GET(timer));
340 now = ecore_time_get();
342 _ecore_timer_set(timer, timer->pending + now, timer->in, timer->func, timer->data);
354 _ecore_timer_shutdown(void)
358 while ((timer = timers))
360 timers = (Ecore_Timer *) eina_inlist_remove(EINA_INLIST_GET(timers), EINA_INLIST_GET(timers));
361 ECORE_MAGIC_SET(timer, ECORE_MAGIC_NONE);
365 while ((timer = suspended))
367 suspended = (Ecore_Timer *) eina_inlist_remove(EINA_INLIST_GET(suspended), EINA_INLIST_GET(suspended));
368 ECORE_MAGIC_SET(timer, ECORE_MAGIC_NONE);
372 timer_current = NULL;
376 _ecore_timer_cleanup(void)
379 int in_use = 0, todo = timers_delete_me, done = 0;
381 if (!timers_delete_me) return;
384 Ecore_Timer *timer = l;
386 l = (Ecore_Timer *) EINA_INLIST_GET(l)->next;
387 if (timer->delete_me)
389 if (timer->references)
394 timers = (Ecore_Timer *) eina_inlist_remove(EINA_INLIST_GET(timers), EINA_INLIST_GET(timer));
395 ECORE_MAGIC_SET(timer, ECORE_MAGIC_NONE);
399 if (timers_delete_me == 0) return;
402 for (l = suspended; l;)
404 Ecore_Timer *timer = l;
406 l = (Ecore_Timer *) EINA_INLIST_GET(l)->next;
407 if (timer->delete_me)
409 if (timer->references)
414 suspended = (Ecore_Timer *) eina_inlist_remove(EINA_INLIST_GET(suspended), EINA_INLIST_GET(timer));
415 ECORE_MAGIC_SET(timer, ECORE_MAGIC_NONE);
419 if (timers_delete_me == 0) return;
423 if ((!in_use) && (timers_delete_me))
425 ERR("%d timers to delete, but they were not found!"
426 "Stats: todo=%d, done=%d, pending=%d, in_use=%d. "
428 timers_delete_me, todo, done, todo - done, in_use);
429 timers_delete_me = 0;
434 _ecore_timer_enable_new(void)
438 if (!timers_added) return;
440 EINA_INLIST_FOREACH(timers, timer) timer->just_added = 0;
444 _ecore_timers_exists(void)
446 Ecore_Timer *timer = timers;
448 while ((timer) && (timer->delete_me))
449 timer = (Ecore_Timer *)EINA_INLIST_GET(timer)->next;
454 static inline Ecore_Timer *
455 _ecore_timer_first_get(void)
457 Ecore_Timer *timer = timers;
459 while ((timer) && ((timer->delete_me) || (timer->just_added)))
460 timer = (Ecore_Timer *) EINA_INLIST_GET(timer)->next;
465 static inline Ecore_Timer *
466 _ecore_timer_after_get(Ecore_Timer *base)
468 Ecore_Timer *timer = (Ecore_Timer *) EINA_INLIST_GET(base)->next;
469 double maxtime = base->at + precision;
471 while ((timer) && ((timer->delete_me) || (timer->just_added)) && (timer->at <= maxtime))
472 timer = (Ecore_Timer *) EINA_INLIST_GET(timer)->next;
474 if ((!timer) || (timer->at > maxtime))
481 _ecore_timer_next_get(void)
485 Ecore_Timer *first, *second;
487 first = _ecore_timer_first_get();
488 if (!first) return -1;
490 second = _ecore_timer_after_get(first);
494 now = ecore_loop_time_get();
495 in = first->at - now;
501 _ecore_timer_reschedule(Ecore_Timer *timer, double when)
503 if ((timer->delete_me) || (timer->frozen)) return;
505 timers = (Ecore_Timer *) eina_inlist_remove(EINA_INLIST_GET(timers), EINA_INLIST_GET(timer));
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.
516 if ((timer->at + timer->in) < (when - 15.0))
517 _ecore_timer_set(timer, when + timer->in, timer->in, timer->func, timer->data);
519 _ecore_timer_set(timer, timer->at + timer->in, timer->in, timer->func, timer->data);
523 _ecore_timer_call(double when)
525 if (!timers) return 0;
526 if (last_check > when)
529 /* User set time backwards */
530 EINA_INLIST_FOREACH(timers, timer) timer->at -= (last_check - when);
536 /* regular main loop, start from head */
537 timer_current = timers;
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);
547 while (timer_current)
549 Ecore_Timer *timer = timer_current;
551 if (timer->at > when)
553 timer_current = NULL; /* ended walk, next should restart. */
557 if ((timer->just_added) || (timer->delete_me))
559 timer_current = (Ecore_Timer*)EINA_INLIST_GET(timer_current)->next;
564 if (!timer->func(timer->data))
566 if (!timer->delete_me) ecore_timer_del(timer);
570 if (timer_current) /* may have changed in recursive main loops */
571 timer_current = (Ecore_Timer *)EINA_INLIST_GET(timer_current)->next;
573 _ecore_timer_reschedule(timer, when);
579 _ecore_timer_set(Ecore_Timer *timer, double at, double in, Ecore_Task_Cb func, void *data)
588 timer->just_added = 1;
590 timer->pending = 0.0;
593 EINA_INLIST_REVERSE_FOREACH(EINA_INLIST_GET(timers), t2)
595 if (timer->at > t2->at)
597 timers = (Ecore_Timer *) eina_inlist_append_relative(EINA_INLIST_GET(timers), EINA_INLIST_GET(timer), EINA_INLIST_GET(t2));
602 timers = (Ecore_Timer *) eina_inlist_prepend(EINA_INLIST_GET(timers), EINA_INLIST_GET(timer));