aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/ecore/src/lib/ecore/ecore_timer.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--libraries/ecore/src/lib/ecore/ecore_timer.c800
1 files changed, 800 insertions, 0 deletions
diff --git a/libraries/ecore/src/lib/ecore/ecore_timer.c b/libraries/ecore/src/lib/ecore/ecore_timer.c
new file mode 100644
index 0000000..9c66545
--- /dev/null
+++ b/libraries/ecore/src/lib/ecore/ecore_timer.c
@@ -0,0 +1,800 @@
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
15typedef void (*Ecore_Timer_Bt_Func)();
16#endif
17
18struct _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
39static void _ecore_timer_set(Ecore_Timer *timer,
40 double at,
41 double in,
42 Ecore_Task_Cb func,
43 void *data);
44#ifdef WANT_ECORE_TIMER_DUMP
45static int _ecore_timer_cmp(const void *d1,
46 const void *d2);
47#endif
48
49static int timers_added = 0;
50static int timers_delete_me = 0;
51static Ecore_Timer *timers = NULL;
52static Ecore_Timer *timer_current = NULL;
53static Ecore_Timer *suspended = NULL;
54static double last_check = 0.0;
55static double precision = 10.0 / 1000000.0;
56
57/**
58 * @addtogroup Ecore_Time_Group
59 *
60 * @{
61 */
62
63/**
64 * Retrieves the current precision used by timer infrastructure.
65 *
66 * @see ecore_timer_precision_set()
67 */
68EAPI double
69ecore_timer_precision_get(void)
70{
71 return precision;
72}
73
74/**
75 * Sets the precision to be used by timer infrastructure.
76 *
77 * When system calculates time to expire the next timer we'll be able
78 * to delay the timer by the given amount so more timers will fit in
79 * the same dispatch, waking up the system less often and thus being
80 * able to save power.
81 *
82 * Be aware that kernel may delay delivery even further, these delays
83 * are always possible due other tasks having higher priorities or
84 * other scheduler policies.
85 *
86 * Example:
87 * We have 2 timers, one that expires in a 2.0s and another that
88 * expires in 2.1s, if precision is 0.1s, then the Ecore will request
89 * for the next expire to happen in 2.1s and not 2.0s and another one
90 * of 0.1 as it would before.
91 *
92 * @note Ecore is smart enough to see if there are timers in the
93 * precision range, if it does not, in our example if no second timer
94 * in (T + precision) existed, then it would use the minimum timeout.
95 *
96 * @param value allowed introduced timeout delay, in seconds.
97 */
98EAPI void
99ecore_timer_precision_set(double value)
100{
101 _ecore_lock();
102
103 if (value < 0.0)
104 {
105 ERR("Precision %f less than zero, ignored", value);
106 goto unlock;
107 }
108 precision = value;
109
110unlock:
111 _ecore_unlock();
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 */
132EAPI Ecore_Timer *
133ecore_timer_add(double in,
134 Ecore_Task_Cb func,
135 const void *data)
136{
137 double now;
138 Ecore_Timer *timer = NULL;
139
140 _ecore_lock();
141 if (!func) goto unlock;
142 if (in < 0.0) in = 0.0;
143 timer = calloc(1, sizeof(Ecore_Timer));
144 if (!timer) goto unlock;
145 ECORE_MAGIC_SET(timer, ECORE_MAGIC_TIMER);
146 now = ecore_time_get();
147
148#ifdef WANT_ECORE_TIMER_DUMP
149 timer->timer_bt_num = backtrace((void **)(timer->timer_bt),
150 ECORE_TIMER_DEBUG_BT_NUM);
151#endif
152
153 _ecore_timer_set(timer, now + in, in, func, (void *)data);
154unlock:
155 _ecore_unlock();
156 return timer;
157}
158
159/**
160 * Creates a timer to call the given function in the given period of time.
161 * @param in The interval in seconds from current loop time.
162 * @param func The given function. If @p func returns 1, the timer is
163 * rescheduled for the next interval @p in.
164 * @param data Data to pass to @p func when it is called.
165 * @return A timer object on success. @c NULL on failure.
166 *
167 * This is the same as ecore_timer_add(), but "now" is the time from
168 * ecore_loop_time_get() not ecore_time_get() as ecore_timer_add() uses. See
169 * ecore_timer_add() for more details.
170 */
171EAPI Ecore_Timer *
172ecore_timer_loop_add(double in,
173 Ecore_Task_Cb func,
174 const void *data)
175{
176 Ecore_Timer *timer;
177
178 _ecore_lock();
179 timer = _ecore_timer_loop_add(in, func, data);
180 _ecore_unlock();
181
182 return timer;
183}
184
185/**
186 * Delete the specified timer from the timer list.
187 * @param timer The timer to delete.
188 * @return The data pointer set for the timer when @ref ecore_timer_add was
189 * called. @c NULL is returned if the function is unsuccessful.
190 *
191 * Note: @p timer must be a valid handle. If the timer function has already
192 * returned 0, the handle is no longer valid (and does not need to be delete).
193 */
194EAPI void *
195ecore_timer_del(Ecore_Timer *timer)
196{
197 void *data = NULL;
198
199 _ecore_lock();
200
201 if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER))
202 {
203 ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER,
204 "ecore_timer_del");
205 goto unlock;
206 }
207
208 data = _ecore_timer_del(timer);
209
210unlock:
211 _ecore_unlock();
212 return data;
213}
214
215/**
216 * Change the interval the timer ticks of. If set during
217 * a timer call, this will affect the next interval.
218 *
219 * @param timer The timer to change.
220 * @param in The interval in seconds.
221 */
222EAPI void
223ecore_timer_interval_set(Ecore_Timer *timer,
224 double in)
225{
226 _ecore_lock();
227
228 if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER))
229 {
230 ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER,
231 "ecore_timer_interval_set");
232 goto unlock;
233 }
234 timer->in = in;
235unlock:
236 _ecore_unlock();
237}
238
239/**
240 * Get the interval the timer ticks on.
241 *
242 * @param timer The timer to retrieve the interval from
243 * @return The interval on success. -1 on failure.
244 */
245EAPI double
246ecore_timer_interval_get(Ecore_Timer *timer)
247{
248 double interval;
249
250 _ecore_lock();
251
252 if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER))
253 {
254 ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER,
255 "ecore_timer_interval_get");
256 interval = -1.0;
257 goto unlock;
258 }
259
260 interval = timer->in;
261unlock:
262 _ecore_unlock();
263 return interval;
264}
265
266/**
267 * Add some delay for the next occurrence of a timer.
268 * This doesn't affect the interval of a timer.
269 *
270 * @param timer The timer to change.
271 * @param add The dalay to add to the next iteration.
272 */
273EAPI void
274ecore_timer_delay(Ecore_Timer *timer,
275 double add)
276{
277 if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER))
278 {
279 ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER,
280 "ecore_timer_delay");
281 return;
282 }
283
284 _ecore_lock();
285 _ecore_timer_delay(timer, add);
286 _ecore_unlock();
287}
288
289/**
290 * Get the pending time regarding a timer.
291 *
292 * @param timer The timer to learn from.
293 * @ingroup Ecore_Time_Group
294 */
295EAPI double
296ecore_timer_pending_get(Ecore_Timer *timer)
297{
298 double now;
299 double ret = 0.0;
300
301 _ecore_lock();
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 goto unlock;
308 }
309
310 now = ecore_time_get();
311
312 if (timer->frozen)
313 ret = timer->pending;
314 else
315 ret = timer->at - now;
316unlock:
317 _ecore_unlock();
318 return ret;
319}
320
321/**
322 * Pauses a running timer.
323 *
324 * @param timer The timer to be paused.
325 *
326 * The timer callback won't be called while the timer is paused. The remaining
327 * time until the timer expires will be saved, so the timer can be resumed with
328 * that same remaining time to expire, instead of expiring instantly. Use
329 * ecore_timer_thaw() to resume it.
330 *
331 * @note Nothing happens if the timer was already paused.
332 *
333 * @see ecore_timer_thaw()
334 */
335EAPI void
336ecore_timer_freeze(Ecore_Timer *timer)
337{
338 double now;
339
340 _ecore_lock();
341
342 if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER))
343 {
344 ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER,
345 "ecore_timer_freeze");
346 goto unlock;
347 }
348
349 /* Timer already frozen */
350 if (timer->frozen)
351 goto unlock;
352
353 timers = (Ecore_Timer *)eina_inlist_remove(EINA_INLIST_GET(timers), EINA_INLIST_GET(timer));
354 suspended = (Ecore_Timer *)eina_inlist_prepend(EINA_INLIST_GET(suspended), EINA_INLIST_GET(timer));
355
356 now = ecore_time_get();
357
358 timer->pending = timer->at - now;
359 timer->at = 0.0;
360 timer->frozen = 1;
361unlock:
362 _ecore_unlock();
363}
364
365/**
366 * Resumes a frozen (paused) timer.
367 *
368 * @param timer The timer to be resumed.
369 *
370 * The timer will be resumed from its previous relative position in time. That
371 * means, if it had X seconds remaining until expire when it was paused, it will
372 * be started now with those same X seconds remaining to expire again. But
373 * notice that the interval time won't be touched by this call or by
374 * ecore_timer_freeze().
375 *
376 * @see ecore_timer_freeze()
377 */
378EAPI void
379ecore_timer_thaw(Ecore_Timer *timer)
380{
381 double now;
382
383 _ecore_lock();
384
385 if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER))
386 {
387 ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER,
388 "ecore_timer_thaw");
389 goto unlock;
390 }
391
392 /* Timer not frozen */
393 if (!timer->frozen)
394 goto unlock;
395
396 suspended = (Ecore_Timer *)eina_inlist_remove(EINA_INLIST_GET(suspended), EINA_INLIST_GET(timer));
397 now = ecore_time_get();
398
399 _ecore_timer_set(timer, timer->pending + now, timer->in, timer->func, timer->data);
400unlock:
401 _ecore_unlock();
402}
403
404EAPI char *
405ecore_timer_dump(void)
406{
407#ifdef WANT_ECORE_TIMER_DUMP
408 Eina_Strbuf *result;
409 char *out;
410 Ecore_Timer *tm;
411 Eina_List *tmp = NULL;
412 int living_timer = 0;
413 int unknow_timer = 0;
414
415 _ecore_lock();
416 result = eina_strbuf_new();
417
418 EINA_INLIST_FOREACH(timers, tm)
419 tmp = eina_list_sorted_insert(tmp, _ecore_timer_cmp, tm);
420
421 EINA_LIST_FREE(tmp, tm)
422 {
423 char **strings;
424 int j;
425
426 if (!tm->frozen && !tm->delete_me)
427 living_timer++;
428
429 strings = backtrace_symbols((void **)tm->timer_bt, tm->timer_bt_num);
430 if (tm->timer_bt_num <= 0 || strings == NULL)
431 {
432 unknow_timer++;
433 continue;
434 }
435
436 eina_strbuf_append_printf(result, "*** timer: %f ***\n", tm->in);
437 if (tm->frozen)
438 eina_strbuf_append(result, "FROZEN\n");
439 if (tm->delete_me)
440 eina_strbuf_append(result, "DELETED\n");
441 for (j = 0; j < tm->timer_bt_num; j++)
442 eina_strbuf_append_printf(result, "%s\n", strings[j]);
443
444 free(strings);
445 }
446
447 eina_strbuf_append_printf(result, "\n***\nThere is %i living timer.\nWe did lost track of %i timers.\n", living_timer, unknow_timer);
448
449 out = eina_strbuf_string_steal(result);
450 eina_strbuf_free(result);
451 _ecore_unlock();
452
453 return out;
454#else
455 return NULL;
456#endif
457}
458
459/**
460 * @}
461 */
462
463Ecore_Timer *
464_ecore_timer_loop_add(double in,
465 Ecore_Task_Cb func,
466 const void *data)
467{
468 double now;
469 Ecore_Timer *timer = NULL;
470
471 if (!func) return timer;
472 if (in < 0.0) in = 0.0;
473 timer = calloc(1, sizeof(Ecore_Timer));
474 if (!timer) return timer;
475 ECORE_MAGIC_SET(timer, ECORE_MAGIC_TIMER);
476 now = ecore_loop_time_get();
477
478#ifdef WANT_ECORE_TIMER_DUMP
479 timer->timer_bt_num = backtrace((void **)(timer->timer_bt),
480 ECORE_TIMER_DEBUG_BT_NUM);
481#endif
482 _ecore_timer_set(timer, now + in, in, func, (void *)data);
483 return timer;
484}
485
486EAPI void
487_ecore_timer_delay(Ecore_Timer *timer,
488 double add)
489{
490 if (timer->frozen)
491 {
492 timer->pending += add;
493 }
494 else
495 {
496 timers = (Ecore_Timer *)eina_inlist_remove(EINA_INLIST_GET(timers), EINA_INLIST_GET(timer));
497 _ecore_timer_set(timer, timer->at + add, timer->in, timer->func, timer->data);
498 }
499}
500
501void *
502_ecore_timer_del(Ecore_Timer *timer)
503{
504 if (timer->frozen && !timer->references)
505 {
506 void *data = timer->data;
507
508 suspended = (Ecore_Timer *)eina_inlist_remove(EINA_INLIST_GET(suspended), EINA_INLIST_GET(timer));
509
510 if (timer->delete_me)
511 timers_delete_me--;
512
513 free(timer);
514 return data;
515 }
516
517 EINA_SAFETY_ON_TRUE_RETURN_VAL(timer->delete_me, NULL);
518 timer->delete_me = 1;
519 timers_delete_me++;
520 return timer->data;
521}
522
523void
524_ecore_timer_shutdown(void)
525{
526 Ecore_Timer *timer;
527
528 while ((timer = timers))
529 {
530 timers = (Ecore_Timer *)eina_inlist_remove(EINA_INLIST_GET(timers), EINA_INLIST_GET(timers));
531 ECORE_MAGIC_SET(timer, ECORE_MAGIC_NONE);
532 free(timer);
533 }
534
535 while ((timer = suspended))
536 {
537 suspended = (Ecore_Timer *)eina_inlist_remove(EINA_INLIST_GET(suspended), EINA_INLIST_GET(suspended));
538 ECORE_MAGIC_SET(timer, ECORE_MAGIC_NONE);
539 free(timer);
540 }
541
542 timer_current = NULL;
543}
544
545void
546_ecore_timer_cleanup(void)
547{
548 Ecore_Timer *l;
549 int in_use = 0, todo = timers_delete_me, done = 0;
550
551 if (!timers_delete_me) return;
552 for (l = timers; l; )
553 {
554 Ecore_Timer *timer = l;
555
556 l = (Ecore_Timer *)EINA_INLIST_GET(l)->next;
557 if (timer->delete_me)
558 {
559 if (timer->references)
560 {
561 in_use++;
562 continue;
563 }
564 timers = (Ecore_Timer *)eina_inlist_remove(EINA_INLIST_GET(timers), EINA_INLIST_GET(timer));
565 ECORE_MAGIC_SET(timer, ECORE_MAGIC_NONE);
566 free(timer);
567 timers_delete_me--;
568 done++;
569 if (timers_delete_me == 0) return;
570 }
571 }
572 for (l = suspended; l; )
573 {
574 Ecore_Timer *timer = l;
575
576 l = (Ecore_Timer *)EINA_INLIST_GET(l)->next;
577 if (timer->delete_me)
578 {
579 if (timer->references)
580 {
581 in_use++;
582 continue;
583 }
584 suspended = (Ecore_Timer *)eina_inlist_remove(EINA_INLIST_GET(suspended), EINA_INLIST_GET(timer));
585 ECORE_MAGIC_SET(timer, ECORE_MAGIC_NONE);
586 free(timer);
587 timers_delete_me--;
588 done++;
589 if (timers_delete_me == 0) return;
590 }
591 }
592
593 if ((!in_use) && (timers_delete_me))
594 {
595 ERR("%d timers to delete, but they were not found!"
596 "Stats: todo=%d, done=%d, pending=%d, in_use=%d. "
597 "reset counter.",
598 timers_delete_me, todo, done, todo - done, in_use);
599 timers_delete_me = 0;
600 }
601}
602
603void
604_ecore_timer_enable_new(void)
605{
606 Ecore_Timer *timer;
607
608 if (!timers_added) return;
609 timers_added = 0;
610 EINA_INLIST_FOREACH(timers, timer) timer->just_added = 0;
611}
612
613int
614_ecore_timers_exists(void)
615{
616 Ecore_Timer *timer = timers;
617
618 while ((timer) && (timer->delete_me))
619 timer = (Ecore_Timer *)EINA_INLIST_GET(timer)->next;
620
621 return !!timer;
622}
623
624static inline Ecore_Timer *
625_ecore_timer_first_get(void)
626{
627 Ecore_Timer *timer = timers;
628
629 while ((timer) && ((timer->delete_me) || (timer->just_added)))
630 timer = (Ecore_Timer *)EINA_INLIST_GET(timer)->next;
631
632 return timer;
633}
634
635static inline Ecore_Timer *
636_ecore_timer_after_get(Ecore_Timer *base)
637{
638 Ecore_Timer *timer = (Ecore_Timer *)EINA_INLIST_GET(base)->next;
639 Ecore_Timer *valid_timer = NULL;
640 double maxtime = base->at + precision;
641
642 while ((timer) && (timer->at < maxtime))
643 {
644 if (!((timer->delete_me) || (timer->just_added)))
645 valid_timer = timer;
646 timer = (Ecore_Timer *)EINA_INLIST_GET(timer)->next;
647 }
648
649 return valid_timer;
650}
651
652double
653_ecore_timer_next_get(void)
654{
655 double now;
656 double in;
657 Ecore_Timer *first, *second;
658
659 first = _ecore_timer_first_get();
660 if (!first) return -1;
661
662 second = _ecore_timer_after_get(first);
663 if (second) first = second;
664
665 now = ecore_loop_time_get();
666 in = first->at - now;
667 if (in < 0) in = 0;
668 return in;
669}
670
671static inline void
672_ecore_timer_reschedule(Ecore_Timer *timer,
673 double when)
674{
675 if ((timer->delete_me) || (timer->frozen)) return;
676
677 timers = (Ecore_Timer *)eina_inlist_remove(EINA_INLIST_GET(timers), EINA_INLIST_GET(timer));
678
679 /* if the timer would have gone off more than 15 seconds ago,
680 * assume that the system hung and set the timer to go off
681 * timer->in from now. this handles system hangs, suspends
682 * and more, so ecore will only "replay" the timers while
683 * the system is suspended if it is suspended for less than
684 * 15 seconds (basically). this also handles if the process
685 * is stopped in a debugger or IO and other handling gets
686 * really slow within the main loop.
687 */
688 if ((timer->at + timer->in) < (when - 15.0))
689 _ecore_timer_set(timer, when + timer->in, timer->in, timer->func, timer->data);
690 else
691 _ecore_timer_set(timer, timer->at + timer->in, timer->in, timer->func, timer->data);
692}
693
694/* assume that we hold the ecore lock when entering this function */
695void
696_ecore_timer_expired_timers_call(double when)
697{
698 /* call the first expired timer until no expired timers exist */
699 while (_ecore_timer_expired_call(when)) ;
700}
701
702/* assume that we hold the ecore lock when entering this function */
703int
704_ecore_timer_expired_call(double when)
705{
706 if (!timers) return 0;
707 if (last_check > when)
708 {
709 Ecore_Timer *timer;
710 /* User set time backwards */
711 EINA_INLIST_FOREACH(timers, timer) timer->at -= (last_check - when);
712 }
713 last_check = when;
714
715 if (!timer_current)
716 {
717 /* regular main loop, start from head */
718 timer_current = timers;
719 }
720 else
721 {
722 /* recursive main loop, continue from where we were */
723 Ecore_Timer *timer_old = timer_current;
724 timer_current = (Ecore_Timer *)EINA_INLIST_GET(timer_current)->next;
725 _ecore_timer_reschedule(timer_old, when);
726 }
727
728 while (timer_current)
729 {
730 Ecore_Timer *timer = timer_current;
731
732 if (timer->at > when)
733 {
734 timer_current = NULL; /* ended walk, next should restart. */
735 return 0;
736 }
737
738 if ((timer->just_added) || (timer->delete_me))
739 {
740 timer_current = (Ecore_Timer *)EINA_INLIST_GET(timer_current)->next;
741 continue;
742 }
743
744 timer->references++;
745 if (!_ecore_call_task_cb(timer->func, timer->data))
746 {
747 if (!timer->delete_me) _ecore_timer_del(timer);
748 }
749 timer->references--;
750
751 if (timer_current) /* may have changed in recursive main loops */
752 timer_current = (Ecore_Timer *)EINA_INLIST_GET(timer_current)->next;
753
754 _ecore_timer_reschedule(timer, when);
755 }
756 return 0;
757}
758
759static void
760_ecore_timer_set(Ecore_Timer *timer,
761 double at,
762 double in,
763 Ecore_Task_Cb func,
764 void *data)
765{
766 Ecore_Timer *t2;
767
768 timers_added = 1;
769 timer->at = at;
770 timer->in = in;
771 timer->func = func;
772 timer->data = data;
773 timer->just_added = 1;
774 timer->frozen = 0;
775 timer->pending = 0.0;
776 if (timers)
777 {
778 EINA_INLIST_REVERSE_FOREACH(EINA_INLIST_GET(timers), t2)
779 {
780 if (timer->at > t2->at)
781 {
782 timers = (Ecore_Timer *)eina_inlist_append_relative(EINA_INLIST_GET(timers), EINA_INLIST_GET(timer), EINA_INLIST_GET(t2));
783 return;
784 }
785 }
786 }
787 timers = (Ecore_Timer *)eina_inlist_prepend(EINA_INLIST_GET(timers), EINA_INLIST_GET(timer));
788}
789
790#ifdef WANT_ECORE_TIMER_DUMP
791static int
792_ecore_timer_cmp(const void *d1,
793 const void *d2)
794{
795 const Ecore_Timer *t1 = d1;
796 const Ecore_Timer *t2 = d2;
797
798 return (int)((t1->in - t2->in) * 100);
799}
800#endif