diff options
Diffstat (limited to '')
-rw-r--r-- | libraries/ecore/src/lib/ecore/ecore_poll.c | 440 |
1 files changed, 440 insertions, 0 deletions
diff --git a/libraries/ecore/src/lib/ecore/ecore_poll.c b/libraries/ecore/src/lib/ecore/ecore_poll.c new file mode 100644 index 0000000..a283cb5 --- /dev/null +++ b/libraries/ecore/src/lib/ecore/ecore_poll.c | |||
@@ -0,0 +1,440 @@ | |||
1 | #ifdef HAVE_CONFIG_H | ||
2 | # include <config.h> | ||
3 | #endif | ||
4 | |||
5 | #include <stdlib.h> | ||
6 | |||
7 | #include "Ecore.h" | ||
8 | #include "ecore_private.h" | ||
9 | |||
10 | struct _Ecore_Poller | ||
11 | { | ||
12 | EINA_INLIST; | ||
13 | ECORE_MAGIC; | ||
14 | int ibit; | ||
15 | unsigned char delete_me : 1; | ||
16 | Ecore_Task_Cb func; | ||
17 | void *data; | ||
18 | }; | ||
19 | |||
20 | static Ecore_Timer *timer = NULL; | ||
21 | static int min_interval = -1; | ||
22 | static int interval_incr = 0; | ||
23 | static int at_tick = 0; | ||
24 | static int just_added_poller = 0; | ||
25 | static int poller_delete_count = 0; | ||
26 | static int poller_walking = 0; | ||
27 | static double poll_interval = 0.125; | ||
28 | static double poll_cur_interval = 0.0; | ||
29 | static double last_tick = 0.0; | ||
30 | static Ecore_Poller *pollers[16] = | ||
31 | { | ||
32 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, | ||
33 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL | ||
34 | }; | ||
35 | static unsigned short poller_counters[16] = | ||
36 | { | ||
37 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
38 | 0, 0, 0, 0, 0, 0, 0, 0 | ||
39 | }; | ||
40 | |||
41 | static void _ecore_poller_next_tick_eval(void); | ||
42 | static Eina_Bool _ecore_poller_cb_timer(void *data); | ||
43 | |||
44 | static void | ||
45 | _ecore_poller_next_tick_eval(void) | ||
46 | { | ||
47 | int i; | ||
48 | double interval; | ||
49 | |||
50 | min_interval = -1; | ||
51 | for (i = 0; i < 15; i++) | ||
52 | { | ||
53 | if (pollers[i]) | ||
54 | { | ||
55 | min_interval = i; | ||
56 | break; | ||
57 | } | ||
58 | } | ||
59 | if (min_interval < 0) | ||
60 | { | ||
61 | /* no pollers */ | ||
62 | if (timer) | ||
63 | { | ||
64 | ecore_timer_del(timer); | ||
65 | timer = NULL; | ||
66 | } | ||
67 | return; | ||
68 | } | ||
69 | interval_incr = (1 << min_interval); | ||
70 | interval = interval_incr * poll_interval; | ||
71 | /* we are at the tick callback - so no need to do inter-tick adjustments | ||
72 | * so we can fasttrack this as t -= last_tick in theory is 0.0 (though | ||
73 | * in practice it will be a very very very small value. also the tick | ||
74 | * callback will adjust the timer interval at the end anyway */ | ||
75 | if (at_tick) | ||
76 | { | ||
77 | if (!timer) | ||
78 | timer = ecore_timer_add(interval, _ecore_poller_cb_timer, NULL); | ||
79 | } | ||
80 | else | ||
81 | { | ||
82 | double t; | ||
83 | |||
84 | if (!timer) | ||
85 | timer = ecore_timer_add(interval, _ecore_poller_cb_timer, NULL); | ||
86 | else | ||
87 | { | ||
88 | t = ecore_time_get(); | ||
89 | if (interval != poll_cur_interval) | ||
90 | { | ||
91 | t -= last_tick; /* time since we last ticked */ | ||
92 | /* delete the timer and reset it to tick off in the new | ||
93 | * time interval. at the tick this will be adjusted */ | ||
94 | ecore_timer_del(timer); | ||
95 | timer = ecore_timer_add(interval - t, | ||
96 | _ecore_poller_cb_timer, NULL); | ||
97 | } | ||
98 | } | ||
99 | } | ||
100 | poll_cur_interval = interval; | ||
101 | } | ||
102 | |||
103 | static Eina_Bool | ||
104 | _ecore_poller_cb_timer(void *data __UNUSED__) | ||
105 | { | ||
106 | int i; | ||
107 | Ecore_Poller *poller, *l; | ||
108 | int changes = 0; | ||
109 | |||
110 | at_tick++; | ||
111 | last_tick = ecore_time_get(); | ||
112 | /* we have 16 counters - each incriments every time the poller counter | ||
113 | * "ticks". it incriments by the minimum interval (which can be 1, 2, 4, | ||
114 | * 7, 16 etc. up to 32768) */ | ||
115 | for (i = 0; i < 15; i++) | ||
116 | { | ||
117 | poller_counters[i] += interval_incr; | ||
118 | /* wrap back to 0 if we exceed out loop count for the counter */ | ||
119 | if (poller_counters[i] >= (1 << i)) poller_counters[i] = 0; | ||
120 | } | ||
121 | |||
122 | just_added_poller = 0; | ||
123 | /* walk the pollers now */ | ||
124 | poller_walking++; | ||
125 | for (i = 0; i < 15; i++) | ||
126 | { | ||
127 | /* if the counter is @ 0 - this means that counter "went off" this | ||
128 | * tick interval, so run all pollers hooked to that counter */ | ||
129 | if (poller_counters[i] == 0) | ||
130 | { | ||
131 | EINA_INLIST_FOREACH(pollers[i], poller) | ||
132 | { | ||
133 | if (!poller->delete_me) | ||
134 | { | ||
135 | if (!poller->func(poller->data)) | ||
136 | { | ||
137 | if (!poller->delete_me) | ||
138 | { | ||
139 | poller->delete_me = 1; | ||
140 | poller_delete_count++; | ||
141 | } | ||
142 | } | ||
143 | } | ||
144 | } | ||
145 | } | ||
146 | } | ||
147 | poller_walking--; | ||
148 | |||
149 | /* handle deletes afterwards */ | ||
150 | if (poller_delete_count > 0) | ||
151 | { | ||
152 | /* FIXME: walk all pollers and remove deleted ones */ | ||
153 | for (i = 0; i < 15; i++) | ||
154 | { | ||
155 | for (l = pollers[i]; l; ) | ||
156 | { | ||
157 | poller = l; | ||
158 | l = (Ecore_Poller *)EINA_INLIST_GET(l)->next; | ||
159 | if (poller->delete_me) | ||
160 | { | ||
161 | pollers[i] = (Ecore_Poller *)eina_inlist_remove(EINA_INLIST_GET(pollers[i]), EINA_INLIST_GET(poller)); | ||
162 | free(poller); | ||
163 | poller_delete_count--; | ||
164 | changes++; | ||
165 | if (poller_delete_count <= 0) break; | ||
166 | } | ||
167 | } | ||
168 | if (poller_delete_count <= 0) break; | ||
169 | } | ||
170 | } | ||
171 | /* if we deleted or added any pollers, then we need to re-evaluate our | ||
172 | * minimum poll interval */ | ||
173 | if ((changes > 0) || (just_added_poller > 0)) | ||
174 | _ecore_poller_next_tick_eval(); | ||
175 | |||
176 | just_added_poller = 0; | ||
177 | poller_delete_count = 0; | ||
178 | |||
179 | at_tick--; | ||
180 | |||
181 | /* if the timer was deleted then there is no point returning 1 - ambiguous | ||
182 | * if we do as it im plies "keep running me" but we have been deleted | ||
183 | * anyway */ | ||
184 | if (!timer) return ECORE_CALLBACK_CANCEL; | ||
185 | |||
186 | /* adjust interval */ | ||
187 | ecore_timer_interval_set(timer, poll_cur_interval); | ||
188 | return ECORE_CALLBACK_RENEW; | ||
189 | } | ||
190 | |||
191 | /** | ||
192 | * @addtogroup Ecore_Poller_Group | ||
193 | * | ||
194 | * @{ | ||
195 | */ | ||
196 | |||
197 | /** | ||
198 | * Sets the time between ticks (in seconds) for the given ticker clock. | ||
199 | * @param type The ticker type to adjust | ||
200 | * @param poll_time The time (in seconds) between ticks of the clock | ||
201 | * | ||
202 | * This will adjust the time between ticks of the given ticker type defined | ||
203 | * by @p type to the time period defined by @p poll_time. | ||
204 | */ | ||
205 | EAPI void | ||
206 | ecore_poller_poll_interval_set(Ecore_Poller_Type type __UNUSED__, | ||
207 | double poll_time) | ||
208 | { | ||
209 | poll_interval = poll_time; | ||
210 | _ecore_poller_next_tick_eval(); | ||
211 | } | ||
212 | |||
213 | /** | ||
214 | * Gets the time between ticks (in seconds) for the given ticker clock. | ||
215 | * @param type The ticker type to query | ||
216 | * @return The time in seconds between ticks of the ticker clock | ||
217 | * | ||
218 | * This will get the time between ticks of the specifider ticker clock. | ||
219 | */ | ||
220 | EAPI double | ||
221 | ecore_poller_poll_interval_get(Ecore_Poller_Type type __UNUSED__) | ||
222 | { | ||
223 | return poll_interval; | ||
224 | } | ||
225 | |||
226 | /** | ||
227 | * Creates a poller to call the given function at a particular tick interval. | ||
228 | * @param type The ticker type to attach the poller to | ||
229 | * @param interval The poll interval | ||
230 | * @param func The given function. If @p func returns 1, the poller is | ||
231 | * rescheduled for the next tick interval. | ||
232 | * @param data Data to pass to @p func when it is called. | ||
233 | * @return A poller object on success. @c NULL on failure. | ||
234 | * | ||
235 | * This function adds a poller callback that is to be called regularly | ||
236 | * along with all other poller callbacks so the pollers are synchronized with | ||
237 | * all other pollers running off the same poller type and at the same tick | ||
238 | * interval. This should be used for polling things when polling is desired | ||
239 | * or required, and you do not have specific requirements on the exact times | ||
240 | * to poll and want to avoid extra process wakeups for polling. This will | ||
241 | * save power as the CPU has more of a chance to go into a low power state | ||
242 | * the longer it is asleep for, so this should be used if you are at all | ||
243 | * power conscious. | ||
244 | * | ||
245 | * The @p type parameter defines the poller tick type (there is a virtual | ||
246 | * clock ticking all the time - though ecore avoids making it tick when | ||
247 | * there will not be any work to do at that tick point). There is only one | ||
248 | * ticker at the moment - that is ECORE_POLLER_CORE. This is here for future | ||
249 | * expansion if multiple clocks with different frequencies are really required. | ||
250 | * The default time between ticks for the ECORE_POLLER_CORE ticker is 0.125 | ||
251 | * seconds. | ||
252 | * | ||
253 | * The @p interval is the number of ticker ticks that will pass by in between | ||
254 | * invocations of the @p func callback. This must be between 1 and 32768 | ||
255 | * inclusive, and must be a power of 2 (i.e. 1, 2, 4, 8, 16, ... 16384, 32768). | ||
256 | * If it is 1, then the function will be called every tick. if it is 2, then it | ||
257 | * will be called every 2nd tick, if it is 8, then every 8th tick etc. Exactly | ||
258 | * which tick is undefined, as only the interval between calls can be defined. | ||
259 | * Ecore will endeavour to keep pollers synchronised and to call as many in | ||
260 | * 1 wakeup event as possible. | ||
261 | * | ||
262 | * This function adds a poller and returns its handle on success and NULL on | ||
263 | * failure. The function @p func will be called at tick intervals described | ||
264 | * above. The function will be passed the @p data pointer as its parameter. | ||
265 | * | ||
266 | * When the poller @p func is called, it must return a value of either | ||
267 | * 1 (or ECORE_CALLBACK_RENEW) or 0 (or ECORE_CALLBACK_CANCEL). If it | ||
268 | * returns 1, it will be called again at the next tick, or if it returns | ||
269 | * 0 it will be deleted automatically making any references/handles for it | ||
270 | * invalid. | ||
271 | */ | ||
272 | EAPI Ecore_Poller * | ||
273 | ecore_poller_add(Ecore_Poller_Type type __UNUSED__, | ||
274 | int interval, | ||
275 | Ecore_Task_Cb func, | ||
276 | const void *data) | ||
277 | { | ||
278 | Ecore_Poller *poller; | ||
279 | int ibit; | ||
280 | |||
281 | if (!func) return NULL; | ||
282 | if (interval < 1) interval = 1; | ||
283 | |||
284 | poller = calloc(1, sizeof(Ecore_Poller)); | ||
285 | if (!poller) return NULL; | ||
286 | ECORE_MAGIC_SET(poller, ECORE_MAGIC_POLLER); | ||
287 | /* interval MUST be a power of 2, so enforce it */ | ||
288 | if (interval < 1) interval = 1; | ||
289 | ibit = -1; | ||
290 | while (interval != 0) | ||
291 | { | ||
292 | ibit++; | ||
293 | interval >>= 1; | ||
294 | } | ||
295 | /* only allow up to 32768 - i.e. ibit == 15, so limit it */ | ||
296 | if (ibit > 15) ibit = 15; | ||
297 | |||
298 | poller->ibit = ibit; | ||
299 | poller->func = func; | ||
300 | poller->data = (void *)data; | ||
301 | pollers[poller->ibit] = (Ecore_Poller *)eina_inlist_prepend(EINA_INLIST_GET(pollers[poller->ibit]), EINA_INLIST_GET(poller)); | ||
302 | if (poller_walking) | ||
303 | just_added_poller++; | ||
304 | else | ||
305 | _ecore_poller_next_tick_eval(); | ||
306 | return poller; | ||
307 | } | ||
308 | |||
309 | /** | ||
310 | * Changes the polling interval rate of @p poller. | ||
311 | * | ||
312 | * @param poller The Ecore_Poller to change the interval of | ||
313 | * @param interval The tick interval to set; must be a power of 2 but <= 32768 | ||
314 | * @return Returns true on success, false on failure | ||
315 | * | ||
316 | * This allows the changing of a poller's polling interval. It is useful when you want to alter | ||
317 | * a poll rate without deleting and re-creating a poller. | ||
318 | */ | ||
319 | EAPI Eina_Bool | ||
320 | ecore_poller_poller_interval_set(Ecore_Poller *poller, | ||
321 | int interval) | ||
322 | { | ||
323 | int ibit; | ||
324 | |||
325 | if (!ECORE_MAGIC_CHECK(poller, ECORE_MAGIC_POLLER)) | ||
326 | { | ||
327 | ECORE_MAGIC_FAIL(poller, ECORE_MAGIC_POLLER, | ||
328 | "ecore_poller_poller_interval_set"); | ||
329 | return EINA_FALSE; | ||
330 | } | ||
331 | |||
332 | /* interval MUST be a power of 2, so enforce it */ | ||
333 | if (interval < 1) interval = 1; | ||
334 | ibit = -1; | ||
335 | while (interval != 0) | ||
336 | { | ||
337 | ibit++; | ||
338 | interval >>= 1; | ||
339 | } | ||
340 | /* only allow up to 32768 - i.e. ibit == 15, so limit it */ | ||
341 | if (ibit > 15) ibit = 15; | ||
342 | /* if interval specified is the same as interval set, return true without wasting time */ | ||
343 | if (poller->ibit == ibit) | ||
344 | return EINA_TRUE; | ||
345 | pollers[poller->ibit] = (Ecore_Poller *)eina_inlist_remove(EINA_INLIST_GET(pollers[poller->ibit]), EINA_INLIST_GET(poller)); | ||
346 | poller->ibit = ibit; | ||
347 | pollers[poller->ibit] = (Ecore_Poller *)eina_inlist_prepend(EINA_INLIST_GET(pollers[poller->ibit]), EINA_INLIST_GET(poller)); | ||
348 | if (poller_walking) | ||
349 | just_added_poller++; | ||
350 | else | ||
351 | _ecore_poller_next_tick_eval(); | ||
352 | return EINA_TRUE; | ||
353 | } | ||
354 | |||
355 | /** | ||
356 | * Gets the polling interval rate of @p poller. | ||
357 | * | ||
358 | * @param poller The Ecore_Poller to change the interval of | ||
359 | * @return Returns the interval, in ticks, that @p poller polls at | ||
360 | * | ||
361 | * This returns a poller's polling interval, or 0 on error. | ||
362 | */ | ||
363 | EAPI int | ||
364 | ecore_poller_poller_interval_get(Ecore_Poller *poller) | ||
365 | { | ||
366 | int ibit, interval = 1; | ||
367 | |||
368 | if (!ECORE_MAGIC_CHECK(poller, ECORE_MAGIC_POLLER)) | ||
369 | { | ||
370 | ECORE_MAGIC_FAIL(poller, ECORE_MAGIC_POLLER, | ||
371 | "ecore_poller_poller_interval_get"); | ||
372 | return 0; | ||
373 | } | ||
374 | |||
375 | ibit = poller->ibit; | ||
376 | while (ibit != 0) | ||
377 | { | ||
378 | ibit--; | ||
379 | interval <<= 1; | ||
380 | } | ||
381 | return interval; | ||
382 | } | ||
383 | |||
384 | /** | ||
385 | * Delete the specified poller from the timer list. | ||
386 | * @param poller The poller to delete. | ||
387 | * @return The data pointer set for the timer when @ref ecore_poller_add was | ||
388 | * called. @c NULL is returned if the function is unsuccessful. | ||
389 | * | ||
390 | * Note: @p poller must be a valid handle. If the poller function has already | ||
391 | * returned 0, the handle is no longer valid (and does not need to be delete). | ||
392 | */ | ||
393 | EAPI void * | ||
394 | ecore_poller_del(Ecore_Poller *poller) | ||
395 | { | ||
396 | void *data; | ||
397 | |||
398 | if (!ECORE_MAGIC_CHECK(poller, ECORE_MAGIC_POLLER)) | ||
399 | { | ||
400 | ECORE_MAGIC_FAIL(poller, ECORE_MAGIC_POLLER, | ||
401 | "ecore_poller_del"); | ||
402 | return NULL; | ||
403 | } | ||
404 | /* we are walking the poller list - a bad idea to remove from it while | ||
405 | * walking it, so just flag it as delete_me and come back to it after | ||
406 | * the loop has finished */ | ||
407 | if (poller_walking > 0) | ||
408 | { | ||
409 | poller_delete_count++; | ||
410 | poller->delete_me = 1; | ||
411 | return poller->data; | ||
412 | } | ||
413 | /* not in loop so safe - delete immediately */ | ||
414 | data = poller->data; | ||
415 | pollers[poller->ibit] = (Ecore_Poller *)eina_inlist_remove(EINA_INLIST_GET(pollers[poller->ibit]), EINA_INLIST_GET(poller)); | ||
416 | free(poller); | ||
417 | _ecore_poller_next_tick_eval(); | ||
418 | return data; | ||
419 | } | ||
420 | |||
421 | /** | ||
422 | * @} | ||
423 | */ | ||
424 | |||
425 | void | ||
426 | _ecore_poller_shutdown(void) | ||
427 | { | ||
428 | int i; | ||
429 | Ecore_Poller *poller; | ||
430 | |||
431 | for (i = 0; i < 15; i++) | ||
432 | { | ||
433 | while ((poller = pollers[i])) | ||
434 | { | ||
435 | pollers[i] = (Ecore_Poller *)eina_inlist_remove(EINA_INLIST_GET(pollers[i]), EINA_INLIST_GET(pollers[i])); | ||
436 | free(poller); | ||
437 | } | ||
438 | } | ||
439 | } | ||
440 | |||