1 /* Copyright (C) 2010 The Android Open Source Project
2 **
3 ** This software is licensed under the terms of the GNU General Public
4 ** License version 2, as published by the Free Software Foundation, and
5 ** may be copied, distributed, and modified under those terms.
6 **
7 ** This program is distributed in the hope that it will be useful,
8 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
9 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 ** GNU General Public License for more details.
11 */
12
13 #include "android/utils/assert.h"
14 #include "android/utils/reflist.h"
15 #include "android/utils/refset.h"
16 #include "android/utils/system.h"
17 #include "android/looper.h"
18 #include "iolooper.h"
19 #include "sockets.h"
20 #include <inttypes.h>
21 #include <limits.h>
22 #include <errno.h>
23
24 /**********************************************************************
25 **********************************************************************
26 *****
27 ***** T I M E R S
28 *****
29 **********************************************************************
30 **********************************************************************/
31
32 typedef struct GLoopTimer GLoopTimer;
33 typedef struct GLoopIo GLoopIo;
34 typedef struct GLooper GLooper;
35
36 struct GLoopTimer {
37 Duration deadline;
38 LoopTimerFunc callback;
39 void* opaque;
40 GLooper* looper;
41 GLoopTimer* activeNext;
42 };
43
44 static Duration glooper_now(Looper* ll);
45
46 static void glooper_addActiveTimer(GLooper* looper, GLoopTimer* timer);
47 static void glooper_delActiveTimer(GLooper* looper, GLoopTimer* timer);
48 static void glooper_addTimer(GLooper* looper, GLoopTimer* timer);
49 static void glooper_delTimer(GLooper* looper, GLoopTimer* timer);
50
51 static void
glooptimer_stop(void * impl)52 glooptimer_stop(void* impl)
53 {
54 GLoopTimer* tt = impl;
55 if (tt->deadline != DURATION_INFINITE) {
56 glooper_delActiveTimer(tt->looper, tt);
57 tt->deadline = DURATION_INFINITE;
58 }
59 }
60
61 static void
glooptimer_startAbsolute(void * impl,Duration deadline_ms)62 glooptimer_startAbsolute(void* impl, Duration deadline_ms)
63 {
64 GLoopTimer* tt = impl;
65
66 /* Stop the timer if it was active */
67 if (tt->deadline != DURATION_INFINITE)
68 glooptimer_stop(tt);
69
70 /* Another way to stop a timer */
71 if (deadline_ms == DURATION_INFINITE)
72 return;
73
74 tt->deadline = deadline_ms;
75 glooper_addActiveTimer(tt->looper, tt);
76 }
77
78 static void
glooptimer_startRelative(void * impl,Duration timeout_ms)79 glooptimer_startRelative(void* impl, Duration timeout_ms)
80 {
81 GLoopTimer* tt = impl;
82
83 if (timeout_ms == DURATION_INFINITE) { /* another way to stop the timer */
84 glooptimer_stop(tt);
85 } else {
86 glooptimer_startAbsolute(tt, timeout_ms + glooper_now((Looper*)tt->looper));
87 }
88 }
89
90 static int
glooptimer_isActive(void * impl)91 glooptimer_isActive(void* impl)
92 {
93 GLoopTimer* tt = impl;
94 return (tt->deadline != DURATION_INFINITE);
95 }
96
97 static void
glooptimer_free(void * impl)98 glooptimer_free(void* impl)
99 {
100 GLoopTimer* tt = impl;
101
102 if (tt->deadline != DURATION_INFINITE)
103 glooptimer_stop(tt);
104
105 glooper_delTimer(tt->looper, tt);
106 AFREE(tt);
107 }
108
109 static const LoopTimerClass glooptimer_class = {
110 glooptimer_startRelative,
111 glooptimer_startAbsolute,
112 glooptimer_stop,
113 glooptimer_isActive,
114 glooptimer_free
115 };
116
117 static void
glooper_timer_init(Looper * looper,LoopTimer * timer,LoopTimerFunc callback,void * opaque)118 glooper_timer_init(Looper* looper,
119 LoopTimer* timer,
120 LoopTimerFunc callback,
121 void* opaque)
122 {
123 GLoopTimer* tt;
124
125 ANEW0(tt);
126
127 tt->deadline = DURATION_INFINITE;
128 tt->callback = callback;
129 tt->opaque = opaque;
130 tt->looper = (GLooper*) looper;
131
132 glooper_addTimer(tt->looper, tt);
133
134 timer->impl = tt;
135 timer->clazz = (LoopTimerClass*) &glooptimer_class;
136 }
137
138 /**********************************************************************
139 **********************************************************************
140 *****
141 ***** I / O
142 *****
143 **********************************************************************
144 **********************************************************************/
145
146 struct GLoopIo {
147 int fd;
148 LoopIoFunc callback;
149 void* opaque;
150 unsigned wanted;
151 unsigned ready;
152 GLooper* looper;
153 };
154
155 static void glooper_delPendingIo(GLooper* looper, GLoopIo* io);
156 static void glooper_addIo(GLooper* looper, GLoopIo* io);
157 static void glooper_delIo(GLooper* looper, GLoopIo* io);
158 static void glooper_modifyFd(GLooper* looper, int fd, int oldwanted, int newwanted);
159
160 /* used to indicate that the set of wanted flags has changed */
161 static void
gloopio_modify(GLoopIo * io,unsigned wanted)162 gloopio_modify(GLoopIo* io, unsigned wanted)
163 {
164 /* If nothing changed, return */
165 if (io->wanted == wanted)
166 return;
167
168 /* If we are pending, and we're not interested by the
169 * current ready flags, remove from list */
170 if (io->ready != 0 && (io->ready & wanted) == 0) {
171 glooper_delPendingIo(io->looper, io);
172 }
173 io->ready &= wanted;
174 glooper_modifyFd(io->looper, io->fd, io->wanted, wanted);
175 io->wanted = wanted;
176 }
177
178 static void
gloopio_wantRead(void * impl)179 gloopio_wantRead(void* impl)
180 {
181 GLoopIo* io = impl;
182 gloopio_modify(io, io->wanted | LOOP_IO_READ);
183 }
184
185 static void
gloopio_wantWrite(void * impl)186 gloopio_wantWrite(void* impl)
187 {
188 GLoopIo* io = impl;
189 gloopio_modify(io, io->wanted | LOOP_IO_WRITE);
190 }
191
192 static void
gloopio_dontWantRead(void * impl)193 gloopio_dontWantRead(void* impl)
194 {
195 GLoopIo* io = impl;
196 gloopio_modify(io, io->wanted & ~LOOP_IO_READ);
197 }
198
199 static void
gloopio_dontWantWrite(void * impl)200 gloopio_dontWantWrite(void* impl)
201 {
202 GLoopIo* io = impl;
203 gloopio_modify(io, io->wanted & ~LOOP_IO_WRITE);
204 }
205
206 static unsigned
gloopio_poll(void * impl)207 gloopio_poll(void* impl)
208 {
209 GLoopIo* io = impl;
210 return io->ready;
211 }
212
213 static void
gloopio_free(void * impl)214 gloopio_free(void* impl)
215 {
216 GLoopIo* io = impl;
217 if (io->ready != 0)
218 glooper_delPendingIo(io->looper, io);
219
220 glooper_delIo(io->looper, io);
221 AFREE(io);
222 }
223
224 static LoopIoClass gloopio_class = {
225 gloopio_wantRead,
226 gloopio_wantWrite,
227 gloopio_dontWantRead,
228 gloopio_dontWantWrite,
229 gloopio_poll,
230 gloopio_free
231 };
232
233 static void
glooper_io_init(Looper * looper,LoopIo * user,int fd,LoopIoFunc callback,void * opaque)234 glooper_io_init(Looper* looper, LoopIo* user, int fd, LoopIoFunc callback, void* opaque)
235 {
236 GLooper* gg = (GLooper*)looper;
237 GLoopIo* io;
238
239 ANEW0(io);
240 io->fd = fd;
241 io->callback = callback;
242 io->opaque = opaque;
243 io->looper = (GLooper*) looper;
244 io->wanted = 0;
245 io->ready = 0;
246
247 socket_set_nonblock(fd);
248
249 glooper_addIo(gg, io);
250
251 user->impl = io;
252 user->clazz = (LoopIoClass*) &gloopio_class;
253 }
254
255 /**********************************************************************
256 **********************************************************************
257 *****
258 ***** L O O P E R
259 *****
260 **********************************************************************
261 **********************************************************************/
262
263 struct GLooper {
264 Looper looper;
265 ARefSet timers[1]; /* set of all timers */
266 GLoopTimer* activeTimers; /* sorted list of active timers */
267
268 ARefSet ios[1]; /* set of all i/o waiters */
269 ARefSet pendingIos[1]; /* list of pending i/o waiters */
270 int numActiveIos; /* number of active LoopIo objects */
271
272 IoLooper* iolooper;
273 int running;
274 };
275
276 static void
glooper_addTimer(GLooper * looper,GLoopTimer * tt)277 glooper_addTimer(GLooper* looper, GLoopTimer* tt)
278 {
279 arefSet_add(looper->timers, tt);
280 }
281
282 static void
glooper_delTimer(GLooper * looper,GLoopTimer * tt)283 glooper_delTimer(GLooper* looper, GLoopTimer* tt)
284 {
285 arefSet_del(looper->timers, tt);
286 }
287
288 static void
glooper_addActiveTimer(GLooper * looper,GLoopTimer * tt)289 glooper_addActiveTimer(GLooper* looper, GLoopTimer* tt)
290 {
291 Duration deadline = tt->deadline;
292 GLoopTimer** pnode = &looper->activeTimers;
293 for (;;) {
294 GLoopTimer* node = *pnode;
295 if (node == NULL || node->deadline > deadline)
296 break;
297 pnode = &node->activeNext;
298 }
299 tt->activeNext = *pnode;
300 *pnode = tt;
301 }
302
303 static void
glooper_delActiveTimer(GLooper * looper,GLoopTimer * tt)304 glooper_delActiveTimer(GLooper* looper, GLoopTimer* tt)
305 {
306 GLoopTimer** pnode = &looper->activeTimers;
307 for (;;) {
308 if (*pnode == NULL)
309 break;
310 if (*pnode == tt) {
311 *pnode = tt->activeNext;
312 tt->activeNext = NULL;
313 break;
314 }
315 pnode = &(*pnode)->activeNext;
316 }
317 }
318
319 static void
glooper_addIo(GLooper * looper,GLoopIo * io)320 glooper_addIo(GLooper* looper, GLoopIo* io)
321 {
322 arefSet_add(looper->ios, io);
323 }
324
325 static void
glooper_delIo(GLooper * looper,GLoopIo * io)326 glooper_delIo(GLooper* looper, GLoopIo* io)
327 {
328 arefSet_del(looper->ios, io);
329 }
330
331 static void
glooper_delPendingIo(GLooper * looper,GLoopIo * io)332 glooper_delPendingIo(GLooper* looper, GLoopIo* io)
333 {
334 arefSet_del(looper->pendingIos, io);
335 }
336
337 static void
glooper_modifyFd(GLooper * looper,int fd,int oldWanted,int newWanted)338 glooper_modifyFd(GLooper* looper, int fd, int oldWanted, int newWanted)
339 {
340 if (oldWanted == 0 && newWanted != 0)
341 looper->numActiveIos += 1;
342
343 if (oldWanted != 0 && newWanted == 0)
344 looper->numActiveIos -= 1;
345
346 iolooper_modify(looper->iolooper, fd, oldWanted, newWanted);
347 }
348
349 static Duration
glooper_now(Looper * ll)350 glooper_now(Looper* ll)
351 {
352 return iolooper_now();
353 }
354
355 static void
glooper_forceQuit(Looper * ll)356 glooper_forceQuit(Looper* ll)
357 {
358 GLooper* looper = (GLooper*)ll;
359 looper->running = 0;
360 }
361
362 static int
glooper_run(Looper * ll,Duration loop_deadline_ms)363 glooper_run(Looper* ll, Duration loop_deadline_ms)
364 {
365 GLooper* looper = (GLooper*) ll;
366 IoLooper* iol = looper->iolooper;
367
368 looper->running = 1;
369
370 while (looper->running)
371 {
372 int ret;
373
374 /* Exit prematurely if we detect that we don't have any active timer
375 * and no active LoopIo
376 */
377 if (looper->numActiveIos == 0 && looper->activeTimers == NULL)
378 return EWOULDBLOCK;
379
380 /* First, compute next deadline */
381 Duration deadline = DURATION_INFINITE;
382
383 if (looper->activeTimers != NULL)
384 deadline = looper->activeTimers->deadline;
385
386 if (deadline > loop_deadline_ms)
387 deadline = loop_deadline_ms;
388
389 ret = iolooper_wait_absolute(iol, deadline);
390 if (ret < 0) { /* error, force stop ! */
391 break;
392 }
393 if (ret > 0) {
394 unsigned ready;
395 GLoopIo* io;
396
397 /* Add io waiters to the pending list */
398 AREFSET_FOREACH(looper->ios, io, {
399 if (io->wanted == 0)
400 continue;
401
402 ready = 0;
403
404 if (iolooper_is_read(iol, io->fd))
405 ready |= LOOP_IO_READ;
406
407 if (iolooper_is_write(iol, io->fd))
408 ready |= LOOP_IO_WRITE;
409
410 io->ready = ready;
411 if (ready != 0) {
412 arefSet_add(looper->pendingIos, io);
413 }
414 });
415 }
416
417 /* Do we have any expired timers here ? */
418 GLoopTimer* pendingTimers = NULL;
419 GLoopTimer** pendingLastP = &pendingTimers;
420
421 deadline = iolooper_now();
422 for (;;) {
423 GLoopTimer* timer = looper->activeTimers;
424 if (timer == NULL || timer->deadline > deadline)
425 break;
426
427 /* remove from active list, and append to pending one */
428 timer->deadline = DURATION_INFINITE;
429 looper->activeTimers = timer->activeNext;
430
431 *pendingLastP = timer;
432 timer->activeNext = NULL;
433 pendingLastP = &timer->activeNext;
434 }
435
436 /* Fire the pending timers, if any. We do that in a separate
437 * step because the callbacks could modify the active list
438 * by starting/stopping other timers.
439 */
440 {
441 GLoopTimer* timer;
442 while ((timer = pendingTimers) != NULL) {
443 pendingTimers = timer->activeNext;
444 timer->activeNext = NULL;
445 timer->callback(timer->opaque);
446 }
447 }
448
449 /* Now fire the pending ios */
450 {
451 GLoopIo* io;
452 AREFSET_FOREACH(looper->pendingIos,io,{
453 io->callback(io->opaque,io->fd,io->ready);
454 });
455 arefSet_clear(looper->pendingIos);
456 }
457
458 if (deadline > loop_deadline_ms)
459 return ETIMEDOUT;
460 }
461 return 0;
462 }
463
464 static void
glooper_free(Looper * ll)465 glooper_free(Looper* ll)
466 {
467 GLooper* looper = (GLooper*)ll;
468
469 arefSet_done(looper->timers);
470 looper->activeTimers = NULL;
471
472 arefSet_done(looper->ios);
473 arefSet_done(looper->pendingIos);
474
475 iolooper_free(looper->iolooper);
476 looper->iolooper = NULL;
477
478 AFREE(looper);
479 }
480
looper_newGeneric(void)481 Looper* looper_newGeneric(void)
482 {
483 GLooper* looper;
484
485 ANEW0(looper);
486
487 looper->iolooper = iolooper_new();
488
489 looper->looper.now = glooper_now;
490 looper->looper.timer_init = glooper_timer_init;
491 looper->looper.io_init = glooper_io_init;
492 looper->looper.run = glooper_run;
493 looper->looper.forceQuit = glooper_forceQuit;
494 looper->looper.destroy = glooper_free;
495
496 /* Our implementation depends on these values being equal */
497 AASSERT_INT(LOOP_IO_READ, IOLOOPER_READ);
498 AASSERT_INT(LOOP_IO_WRITE, IOLOOPER_WRITE);
499
500 return &looper->looper;
501 }
502