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