Tizen 2.1 base
[framework/uifw/ecore.git] / src / lib / ecore / ecore_poll.c
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 GENERIC_ALLOC_SIZE_DECLARE(Ecore_Poller);
20
21 static Ecore_Timer *timer = NULL;
22 static int min_interval = -1;
23 static int interval_incr = 0;
24 static int at_tick = 0;
25 static int just_added_poller = 0;
26 static int poller_delete_count = 0;
27 static int poller_walking = 0;
28 static double poll_interval = 0.125;
29 static double poll_cur_interval = 0.0;
30 static double last_tick = 0.0;
31 static Ecore_Poller *pollers[16] =
32 {
33    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
34    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
35 };
36 static unsigned short poller_counters[16] =
37 {
38    0, 0, 0, 0, 0, 0, 0, 0,
39    0, 0, 0, 0, 0, 0, 0, 0
40 };
41
42 static void      _ecore_poller_next_tick_eval(void);
43 static Eina_Bool _ecore_poller_cb_timer(void *data);
44
45 static void
46 _ecore_poller_next_tick_eval(void)
47 {
48    int i;
49    double interval;
50
51    min_interval = -1;
52    for (i = 0; i < 15; i++)
53      {
54         if (pollers[i])
55           {
56              min_interval = i;
57              break;
58           }
59      }
60    if (min_interval < 0)
61      {
62         /* no pollers */
63          if (timer)
64            {
65               ecore_timer_del(timer);
66               timer = NULL;
67            }
68          return;
69      }
70    interval_incr = (1 << min_interval);
71    interval = interval_incr * poll_interval;
72    /* we are at the tick callback - so no need to do inter-tick adjustments
73     * so we can fasttrack this as t -= last_tick in theory is 0.0 (though
74     * in practice it will be a very very very small value. also the tick
75     * callback will adjust the timer interval at the end anyway */
76    if (at_tick)
77      {
78         if (!timer)
79           timer = ecore_timer_add(interval, _ecore_poller_cb_timer, NULL);
80      }
81    else
82      {
83         double t;
84
85         if (!timer)
86           timer = ecore_timer_add(interval, _ecore_poller_cb_timer, NULL);
87         else
88           {
89              t = ecore_time_get();
90              if (interval != poll_cur_interval)
91                {
92                   t -= last_tick; /* time since we last ticked */
93      /* delete the timer and reset it to tick off in the new
94       * time interval. at the tick this will be adjusted */
95                   ecore_timer_del(timer);
96                   timer = ecore_timer_add(interval - t,
97                                           _ecore_poller_cb_timer, NULL);
98                }
99           }
100      }
101    poll_cur_interval = interval;
102 }
103
104 static Eina_Bool
105 _ecore_poller_cb_timer(void *data __UNUSED__)
106 {
107    int i;
108    Ecore_Poller *poller, *l;
109    int changes = 0;
110
111    at_tick++;
112    last_tick = ecore_time_get();
113    /* we have 16 counters - each increments every time the poller counter
114     * "ticks". it increments by the minimum interval (which can be 1, 2, 4,
115     * 7, 16 etc. up to 32768) */
116    for (i = 0; i < 15; i++)
117      {
118         poller_counters[i] += interval_incr;
119         /* wrap back to 0 if we exceed out loop count for the counter */
120         if (poller_counters[i] >= (1 << i)) poller_counters[i] = 0;
121      }
122
123    just_added_poller = 0;
124    /* walk the pollers now */
125    poller_walking++;
126    for (i = 0; i < 15; i++)
127      {
128         /* if the counter is @ 0 - this means that counter "went off" this
129          * tick interval, so run all pollers hooked to that counter */
130           if (poller_counters[i] == 0)
131             {
132                EINA_INLIST_FOREACH(pollers[i], poller)
133                  {
134                     if (!poller->delete_me)
135                       {
136                          if (!poller->func(poller->data))
137                            {
138                               if (!poller->delete_me)
139                                 {
140                                    poller->delete_me = 1;
141                                    poller_delete_count++;
142                                 }
143                            }
144                       }
145                  }
146             }
147      }
148    poller_walking--;
149
150    /* handle deletes afterwards */
151    if (poller_delete_count > 0)
152      {
153         /* FIXME: walk all pollers and remove deleted ones */
154          for (i = 0; i < 15; i++)
155            {
156               for (l = pollers[i]; l; )
157                 {
158                    poller = l;
159                    l = (Ecore_Poller *)EINA_INLIST_GET(l)->next;
160                    if (poller->delete_me)
161                      {
162                         pollers[i] = (Ecore_Poller *)eina_inlist_remove(EINA_INLIST_GET(pollers[i]), EINA_INLIST_GET(poller));
163                         ecore_poller_mp_free(poller);
164                         poller_delete_count--;
165                         changes++;
166                         if (poller_delete_count <= 0) break;
167                      }
168                 }
169               if (poller_delete_count <= 0) break;
170            }
171      }
172    /* if we deleted or added any pollers, then we need to re-evaluate our
173     * minimum poll interval */
174    if ((changes > 0) || (just_added_poller > 0))
175      _ecore_poller_next_tick_eval();
176
177    just_added_poller = 0;
178    poller_delete_count = 0;
179
180    at_tick--;
181
182    /* if the timer was deleted then there is no point returning 1 - ambiguous
183     * if we do as it implies keep running me" but we have been deleted
184     * anyway */
185    if (!timer) return ECORE_CALLBACK_CANCEL;
186
187    /* adjust interval */
188    ecore_timer_interval_set(timer, poll_cur_interval);
189    return ECORE_CALLBACK_RENEW;
190 }
191
192 EAPI void
193 ecore_poller_poll_interval_set(Ecore_Poller_Type type __UNUSED__,
194                                double            poll_time)
195 {
196    EINA_MAIN_LOOP_CHECK_RETURN;
197
198    if (poll_time < 0.0)
199      {
200         ERR("Poll time %f less than zero, ignored", poll_time);
201         return;
202      }
203
204    poll_interval = poll_time;
205    _ecore_poller_next_tick_eval();
206 }
207
208 EAPI double
209 ecore_poller_poll_interval_get(Ecore_Poller_Type type __UNUSED__)
210 {
211    EINA_MAIN_LOOP_CHECK_RETURN_VAL(0.0);
212    return poll_interval;
213 }
214
215 EAPI Ecore_Poller *
216 ecore_poller_add(Ecore_Poller_Type type __UNUSED__,
217                  int               interval,
218                  Ecore_Task_Cb     func,
219                  const void       *data)
220 {
221    Ecore_Poller *poller;
222    int ibit;
223
224    EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
225    if (!func) return NULL;
226    if (interval < 1) interval = 1;
227
228    poller = ecore_poller_calloc(1);
229    if (!poller) return NULL;
230    ECORE_MAGIC_SET(poller, ECORE_MAGIC_POLLER);
231    /* interval MUST be a power of 2, so enforce it */
232    if (interval < 1) interval = 1;
233    ibit = -1;
234    while (interval != 0)
235      {
236         ibit++;
237         interval >>= 1;
238      }
239    /* only allow up to 32768 - i.e. ibit == 15, so limit it */
240    if (ibit > 15) ibit = 15;
241
242    poller->ibit = ibit;
243    poller->func = func;
244    poller->data = (void *)data;
245    pollers[poller->ibit] = (Ecore_Poller *)eina_inlist_prepend(EINA_INLIST_GET(pollers[poller->ibit]), EINA_INLIST_GET(poller));
246    if (poller_walking)
247      just_added_poller++;
248    else
249      _ecore_poller_next_tick_eval();
250    return poller;
251 }
252
253 EAPI Eina_Bool
254 ecore_poller_poller_interval_set(Ecore_Poller *poller,
255                                  int           interval)
256 {
257    int ibit;
258
259    EINA_MAIN_LOOP_CHECK_RETURN_VAL(EINA_FALSE);
260    if (!ECORE_MAGIC_CHECK(poller, ECORE_MAGIC_POLLER))
261      {
262         ECORE_MAGIC_FAIL(poller, ECORE_MAGIC_POLLER,
263                          "ecore_poller_poller_interval_set");
264         return EINA_FALSE;
265      }
266
267    /* interval MUST be a power of 2, so enforce it */
268    if (interval < 1) interval = 1;
269    ibit = -1;
270    while (interval != 0)
271      {
272         ibit++;
273         interval >>= 1;
274      }
275    /* only allow up to 32768 - i.e. ibit == 15, so limit it */
276    if (ibit > 15) ibit = 15;
277    /* if interval specified is the same as interval set, return true without wasting time */
278    if (poller->ibit == ibit)
279      return EINA_TRUE;
280    pollers[poller->ibit] = (Ecore_Poller *)eina_inlist_remove(EINA_INLIST_GET(pollers[poller->ibit]), EINA_INLIST_GET(poller));
281    poller->ibit = ibit;
282    pollers[poller->ibit] = (Ecore_Poller *)eina_inlist_prepend(EINA_INLIST_GET(pollers[poller->ibit]), EINA_INLIST_GET(poller));
283    if (poller_walking)
284      just_added_poller++;
285    else
286      _ecore_poller_next_tick_eval();
287    return EINA_TRUE;
288 }
289
290 EAPI int
291 ecore_poller_poller_interval_get(Ecore_Poller *poller)
292 {
293    int ibit, interval = 1;
294
295    EINA_MAIN_LOOP_CHECK_RETURN_VAL(0);
296    if (!ECORE_MAGIC_CHECK(poller, ECORE_MAGIC_POLLER))
297      {
298         ECORE_MAGIC_FAIL(poller, ECORE_MAGIC_POLLER,
299                          "ecore_poller_poller_interval_get");
300         return 0;
301      }
302
303    ibit = poller->ibit;
304    while (ibit != 0)
305      {
306         ibit--;
307         interval <<= 1;
308      }
309    return interval;
310 }
311
312 EAPI void *
313 ecore_poller_del(Ecore_Poller *poller)
314 {
315    void *data;
316
317    EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
318    if (!ECORE_MAGIC_CHECK(poller, ECORE_MAGIC_POLLER))
319      {
320         ECORE_MAGIC_FAIL(poller, ECORE_MAGIC_POLLER,
321                          "ecore_poller_del");
322         return NULL;
323      }
324    /* we are walking the poller list - a bad idea to remove from it while
325     * walking it, so just flag it as delete_me and come back to it after
326     * the loop has finished */
327    if (poller_walking > 0)
328      {
329         poller_delete_count++;
330         poller->delete_me = 1;
331         return poller->data;
332      }
333    /* not in loop so safe - delete immediately */
334    data = poller->data;
335    pollers[poller->ibit] = (Ecore_Poller *)eina_inlist_remove(EINA_INLIST_GET(pollers[poller->ibit]), EINA_INLIST_GET(poller));
336    ecore_poller_mp_free(poller);
337    _ecore_poller_next_tick_eval();
338    return data;
339 }
340
341 /**
342  * @}
343  */
344
345 void
346 _ecore_poller_shutdown(void)
347 {
348    int i;
349    Ecore_Poller *poller;
350
351    for (i = 0; i < 15; i++)
352      {
353         while ((poller = pollers[i]))
354           {
355              pollers[i] = (Ecore_Poller *)eina_inlist_remove(EINA_INLIST_GET(pollers[i]), EINA_INLIST_GET(pollers[i]));
356              ecore_poller_mp_free(poller);
357           }
358      }
359 }
360