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