summaryrefslogtreecommitdiff
path: root/legacy/ecore/src/lib/ecore/ecore_poll.c
diff options
context:
space:
mode:
authorCarsten Haitzler <raster@rasterman.com>2008-01-11 07:33:57 +0000
committerCarsten Haitzler <raster@rasterman.com>2008-01-11 07:33:57 +0000
commitc1441e1c3a05694e0fc8e85b2cf29319aec967dc (patch)
treede9be6b702bd9d76d53ca4cabce068e1ae0b6e7f /legacy/ecore/src/lib/ecore/ecore_poll.c
parent2909ac19e4c853a86f1ebef923508f16afd9e97c (diff)
e:
1. configure/build changes to allow cross-compiling painlessly 2. pager module namespace changes - this was still dirty afdter the namespace cleanup, so clean it up 3. add a powersave subsystem - doesnt have an "automatic" way to turn on and off right now, this i think is best provided by modules (that do things like monitor acpi status's (eg close lid of laptop), AC power status etc. etc. this allows e to nicely defer "power" expensive actions to avoid disk spinups etc. 4. move to use the new ecore poller system - discussed long ago as part of power management/saving issues. now it exists 5. add a canvas idle flush call that helsp cope with the new shm greedy software x11 engine stuff 6. use the new powersave subsystem where appropriate 7. fix non-zeroed/initted memory access in e_fm_main 8. fix mem leak for e menus 9. remove ipc handlers for changed/removed config values 10. use animaotr not timer for menu scrolls - then menu scrolls obey the fps config 11. fix up timer/poll happienss of cursor idle stuff 12. remove avoid damage from popups for now - causing problems 13. change battery and temp readouts to b e shorter so they fit 14. pager can emit signals on focus change for mini-windows now 15. temperature module now uses a slave process and uses stdin/out to talk to it and get output - this makes e smoother as in my expereicne i found getting the temp on my laptop actually took like 200ms so e "hang" for 200ms while reading the acpi files - so now the subprocess does it and just writesa back to e when it gets it. ecore: 1. add ecore_pollers. see the documentation on them in doxygen comments :) 2. fix timers to only go off when they have to - bug there that made e's select time out a LOT more than it needed to. defensive coding hid the problem. now fixed. e should be much more power friendly now. 3. formatting/niceness in ecore_exe stuff 4. some comments on comments with SIGIO ideas vs. select 5. add call to be able to add an idle enterer at the start of the list of them, not just the end (as has been the default) 6. fix ecore_evas to support auto evas idler calls after 0.5 secs of idle in all canvases - and to do it right 7. if argb destination - set the shape EVENT shape (to mask out events in transparent regions much like shape does withotu translucency) 8. in ecore_x add support for the event shape evas: 1. fix cache to work properly and not just always fill up (as it seemed to like to think cahce useage dropped below 0 when it didnt and thus just over-fill) 2. software x11 engine now ONLY uses shm segments - no ximages over the socket. this ximage hack was there to avoid the 2 round trips involved in setting up an shm image - now i mitigated that wih an shm image cache pool. it keeps shm images around and repurposes them for new update regions if appropriate. this means many fewer shm creates (about 1/100th the number) and since we recycle the memory less 0 memory page filling by the kernel - in the end, i recorded about a 10-20% speedup over the old software x11 engine. simple tests i have seen up to 120% speedups. idle flush now does something - it frees all the cached shm segments. it has a hard-coded limit of 4mb worth of shm segments (or 32 segments - whichever comes first) to keep around. once can never complain much about speedups methinks :). also evas will defer sync until the NEXT frame is written - this means evas can calculate the next frame of data while x dma's/copies the images to the screen at the same time (if you hve a dual core or multi-cpu machnike or your xserver is able to use DMA to copy image data to the screen/video ram then this should see a decent speedup). SVN revision: 33448
Diffstat (limited to 'legacy/ecore/src/lib/ecore/ecore_poll.c')
-rw-r--r--legacy/ecore/src/lib/ecore/ecore_poll.c352
1 files changed, 352 insertions, 0 deletions
diff --git a/legacy/ecore/src/lib/ecore/ecore_poll.c b/legacy/ecore/src/lib/ecore/ecore_poll.c
new file mode 100644
index 0000000000..88e4291250
--- /dev/null
+++ b/legacy/ecore/src/lib/ecore/ecore_poll.c
@@ -0,0 +1,352 @@
1#include "ecore_private.h"
2#include "Ecore.h"
3
4static Ecore_Timer *timer = NULL;
5static int min_interval = -1;
6static int interval_incr = 0;
7static int at_tick = 0;
8static int just_added_poller = 0;
9static int poller_delete_count = 0;
10static int poller_walking = 0;
11static double poll_interval = 0.125;
12static double poll_cur_interval = 0.0;
13static double last_tick = 0.0;
14static Ecore_Poller *pollers[16] =
15{
16 NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
17 NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL
18};
19static unsigned short poller_counters[16] =
20{
21 0,0,0,0,0,0,0,0,
22 0,0,0,0,0,0,0,0
23};
24
25static void _ecore_poller_next_tick_eval(void);
26static int _ecore_poller_cb_timer(void *data);
27
28static void
29_ecore_poller_next_tick_eval(void)
30{
31 int i;
32 double interval;
33
34 min_interval = -1;
35 for (i = 0; i < 15; i++)
36 {
37 if (pollers[i])
38 {
39 min_interval = i;
40 break;
41 }
42 }
43 if (min_interval < 0)
44 {
45 /* no pollers */
46 if (timer)
47 {
48 ecore_timer_del(timer);
49 timer = NULL;
50 }
51 return;
52 }
53 interval_incr = (1 << min_interval);
54 interval = interval_incr * poll_interval;
55 /* we are at the tick callback - so no need to do inter-tick adjustments
56 * so we can fasttrack this as t -= last_tick in theory is 0.0 (though
57 * in practice it will be a very very very small value. also the tick
58 * callback will adjust the timer interval at the end anyway */
59 if (at_tick)
60 {
61 if (!timer)
62 timer = ecore_timer_add(interval, _ecore_poller_cb_timer, NULL);
63 }
64 else
65 {
66 double t;
67
68 if (!timer)
69 timer = ecore_timer_add(interval, _ecore_poller_cb_timer, NULL);
70 else
71 {
72 t = ecore_time_get();
73 if (interval != poll_cur_interval)
74 {
75 t -= last_tick; /* time since we last ticked */
76 /* delete the timer and reset it to tick off in the new
77 * time interval. at the tick this will be adjusted */
78 ecore_timer_del(timer);
79 timer = ecore_timer_add(interval - t,
80 _ecore_poller_cb_timer, NULL);
81 }
82 }
83 }
84 poll_cur_interval = interval;
85}
86
87static int
88_ecore_poller_cb_timer(void *data)
89{
90 int i;
91 Ecore_List2 *l;
92 Ecore_Poller *poller;
93 int changes = 0;
94
95 at_tick++;
96 last_tick = ecore_time_get();
97 /* we have 16 counters - each incriments every time the poller counter
98 * "ticks". it incriments by the minimum interval (which can be 1, 2, 4,
99 * 7, 16 etc. up to 32768) */
100 for (i = 0; i < 15; i++)
101 {
102 poller_counters[i] += interval_incr;
103 /* wrap back to 0 if we exceed out loop count for the counter */
104 if (poller_counters[i] >= (1 << i)) poller_counters[i] = 0;
105 }
106
107 just_added_poller = 0;
108 /* walk the pollers now */
109 poller_walking++;
110 for (i = 0; i < 15; i++)
111 {
112 /* if the counter is @ 0 - this means that counter "went off" this
113 * tick interval, so run all pollers hooked to that counter */
114 if (poller_counters[i] == 0)
115 {
116 for (l = (Ecore_List2 *)pollers[i]; l; l = l->next)
117 {
118 poller = (Ecore_Poller *)l;
119 if (!poller->delete_me)
120 {
121 if (!poller->func(poller->data))
122 {
123 if (!poller->delete_me)
124 {
125 poller->delete_me = 1;
126 poller_delete_count++;
127 }
128 }
129 }
130 }
131 }
132 }
133 poller_walking--;
134
135 /* handle deletes afterwards */
136 if (poller_delete_count > 0)
137 {
138 /* FIXME: walk all pollers and remove deleted ones */
139 for (i = 0; i < 15; i++)
140 {
141 for (l = (Ecore_List2 *)pollers[i]; l;)
142 {
143 poller = (Ecore_Poller *)l;
144 l = l->next;
145 if (poller->delete_me)
146 {
147 pollers[poller->ibit] = _ecore_list2_remove(pollers[poller->ibit], poller);
148 free(poller);
149 poller_delete_count--;
150 changes++;
151 if (poller_delete_count <= 0) break;
152 }
153 }
154 if (poller_delete_count <= 0) break;
155 }
156 }
157 /* if we deleted or added any pollers, then we need to re-evaluate our
158 * minimum poll interval */
159 if ((changes > 0) || (just_added_poller > 0))
160 _ecore_poller_next_tick_eval();
161
162 just_added_poller = 0;
163 poller_delete_count = 0;
164
165 at_tick--;
166
167 /* if the timer was deleted then there is no point returning 1 - ambiguous
168 * if we do as it im plies "keep running me" but we have been deleted
169 * anyway */
170 if (!timer) return 0;
171
172 /* adjust interval */
173 ecore_timer_interval_set(timer, poll_cur_interval);
174 return 1;
175}
176
177/**
178 * @defgroup Ecore_Poll_Group Ecore Poll Functions
179 *
180 * These functions are for the need to poll information, but provide a shared
181 * abstracted API to pool such polling to minimise wakeup and ensure all the
182 * polling happens in as few spots as possible areound a core poll interval.
183 * For now only 1 core poller type is supprted: ECORE_POLLER_CORE
184 */
185
186
187/**
188 * Sets the time between ticks (in seconds) for the given ticker clock.
189 * @param type The ticker type to adjust
190 * @param poll_time The time (in seconds) between ticks of the clock
191 * @ingroup Ecore_Poller_Group
192 *
193 * This will adjust the time between ticks of the given ticker type defined
194 * by @p type to the time period defined by @p poll_time.
195 */
196EAPI void
197ecore_poller_poll_interval_set(Ecore_Poller_Type type, double poll_time)
198{
199 poll_interval = poll_time;
200 _ecore_poller_next_tick_eval();
201}
202
203/**
204 * Gets the time between ticks (in seconds) for the fiven ticker clock.
205 * @param type The ticker type to query
206 * @return The time in seconds between ticks of the ticker clock
207 * @ingroup Ecore_Poller_Group
208 *
209 * This will get the time between ticks of the specifider ticker clock.
210 */
211EAPI double
212ecore_poller_poll_interval_get(Ecore_Poller_Type type)
213{
214 return poll_interval;
215}
216
217/**
218 * Creates a poller to call the given function at a particular tick interval.
219 * @param type The ticker type to attach the poller to
220 * @param interval The poll interval
221 * @param func The given function. If @p func returns 1, the poller is
222 * rescheduled for the next tick interval.
223 * @param data Data to pass to @p func when it is called.
224 * @return A poller object on success. @c NULL on failure.
225 * @ingroup Ecore_Poller_Group
226 *
227 * This function adds a poller callback that is to be called regularly
228 * along with all other poller callbacks so the pollers are synchronized with
229 * all other pollers running off the same poller type and at the same tick
230 * interval. This should be used for polling things when polling is desired
231 * or required, and you do not have specific requirements on the exact times
232 * to poll and want to avoid extra process wakeups for polling. This will
233 * save power as the CPU has more of a chance to go into a low power state
234 * the longer it is asleep for, so this should be used if you are at all
235 * power conscious.
236 *
237 * The @p type parameter defines the poller tick type (there is a virtual
238 * clock ticking all the time - though ecore avoids making it tick when
239 * there will not be any work to do at that tick point). There is only one
240 * ticker at the moment - that is ECORE_POLLER_CORE. This is here for future
241 * expansion if multiple clocks with different frequencies are really required.
242 * The default time between ticks for the ECORE_POLLER_CORE ticker is 0.125
243 * seconds.
244 *
245 * The @p interval is the number of ticker ticks that will pass by in between
246 * invocations of the @p func callback. This must be between 1 and 32768
247 * inclusive, and must be a power of 2 (i.e. 1, 2, 4, 8, 16, ... 16384, 32768).
248 * If it is 1, then the function will be called every tick. if it is 2, then it
249 * will be called every 2nd tick, if it is 8, then every 8th tick etc. Exactly
250 * which tick is undefined, as only the interval between calls can be defined.
251 * Ecore will endeavour to keep pollers synchronised and to call as many in
252 * 1 wakeup event as possible.
253 *
254 * This function adds a poller and returns its handle on success and NULL on
255 * failure. The function @p func will be called at tick intervals described
256 * above. The function will be passed the @p data pointer as its parameter.
257 *
258 * When the poller @p func is called, it must return a value of either 1 or 0.
259 * If it returns 1, it will be called again at the next tick, or if it returns
260 * 0 it will be deleted automatically making any references/handles for it
261 * invalid.
262 */
263EAPI Ecore_Poller *
264ecore_poller_add(Ecore_Poller_Type type, int interval, int (*func) (void *data), const void *data)
265{
266 Ecore_Poller *poller;
267 int ibit;
268
269 if (!func) return NULL;
270 if (interval < 1) interval = 1;
271
272 poller = calloc(1, sizeof(Ecore_Poller));
273 if (!poller) return NULL;
274 ECORE_MAGIC_SET(poller, ECORE_MAGIC_POLLER);
275 /* interval MUST be a power of 2, so enforce it */
276 if (interval < 1) interval = 1;
277 ibit = -1;
278 while (interval != 0)
279 {
280 ibit++;
281 interval >>= 1;
282 }
283 /* only allow up to 32768 - i.e. ibit == 15, so limit it */
284 if (ibit > 15) ibit = 15;
285
286 poller->ibit = ibit;
287 poller->func = func;
288 poller->data = (void *)data;
289 pollers[poller->ibit] = _ecore_list2_prepend(pollers[poller->ibit], poller);
290 if (poller_walking)
291 just_added_poller++;
292 else
293 _ecore_poller_next_tick_eval();
294 return poller;
295}
296
297/**
298 * Delete the specified poller from the timer list.
299 * @param poller The poller to delete.
300 * @return The data pointer set for the timer when @ref ecore_poller_add was
301 * called. @c NULL is returned if the function is unsuccessful.
302 * @ingroup Ecore_Poller_Group
303 *
304 * Note: @p poller must be a valid handle. If the poller function has already
305 * returned 0, the handle is no longer valid (and does not need to be delete).
306 */
307EAPI void *
308ecore_poller_del(Ecore_Poller *poller)
309{
310 void *data;
311
312 if (!ECORE_MAGIC_CHECK(poller, ECORE_MAGIC_POLLER))
313 {
314 ECORE_MAGIC_FAIL(poller, ECORE_MAGIC_POLLER,
315 "ecore_poller_del");
316 return NULL;
317 }
318 /* we are walking the poller list - a bad idea to remove from it while
319 * walking it, so just flag it as delete_me and come back to it after
320 * the loop has finished */
321 if (poller_walking > 0)
322 {
323 poller_delete_count++;
324 poller->delete_me = 1;
325 return poller->data;
326 }
327 /* not in loop so safe - delete immediately */
328 data = poller->data;
329 pollers[poller->ibit] = _ecore_list2_remove(pollers[poller->ibit], poller);
330 free(poller);
331 _ecore_poller_next_tick_eval();
332 return data;
333}
334
335void
336_ecore_poller_shutdown(void)
337{
338 int i;
339 Ecore_List2 *l;
340 Ecore_Poller *poller;
341
342 for (i = 0; i < 15; i++)
343 {
344 for (l = (Ecore_List2 *)pollers[i]; l;)
345 {
346 poller = (Ecore_Poller *)l;
347 l = l->next;
348 pollers[poller->ibit] = _ecore_list2_remove(pollers[poller->ibit], poller);
349 free(poller);
350 }
351 }
352}