aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/ecore/src/lib/ecore/ecore_poll.c
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/ecore/src/lib/ecore/ecore_poll.c')
-rw-r--r--libraries/ecore/src/lib/ecore/ecore_poll.c440
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
10struct _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
20static Ecore_Timer *timer = NULL;
21static int min_interval = -1;
22static int interval_incr = 0;
23static int at_tick = 0;
24static int just_added_poller = 0;
25static int poller_delete_count = 0;
26static int poller_walking = 0;
27static double poll_interval = 0.125;
28static double poll_cur_interval = 0.0;
29static double last_tick = 0.0;
30static Ecore_Poller *pollers[16] =
31{
32 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
33 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
34};
35static 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
41static void _ecore_poller_next_tick_eval(void);
42static Eina_Bool _ecore_poller_cb_timer(void *data);
43
44static 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
103static 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 */
205EAPI void
206ecore_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 */
220EAPI double
221ecore_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 */
272EAPI Ecore_Poller *
273ecore_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 */
319EAPI Eina_Bool
320ecore_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 */
363EAPI int
364ecore_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 */
393EAPI void *
394ecore_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
425void
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