diff options
-rw-r--r-- | android/looper-generic.c | 31 | ||||
-rw-r--r-- | android/looper-qemu.c | 11 | ||||
-rw-r--r-- | android/looper.h | 77 | ||||
-rw-r--r-- | iolooper-select.c | 16 |
4 files changed, 111 insertions, 24 deletions
diff --git a/android/looper-generic.c b/android/looper-generic.c index b471c50..6ec0db4 100644 --- a/android/looper-generic.c +++ b/android/looper-generic.c @@ -16,8 +16,10 @@ #include "android/utils/system.h" #include "android/looper.h" #include "iolooper.h" +#include "sockets.h" #include <inttypes.h> #include <limits.h> +#include <errno.h> /********************************************************************** ********************************************************************** @@ -230,9 +232,12 @@ glooper_io_init(Looper* looper, LoopIo* user, int fd, LoopIoFunc callback, void* io->fd = fd; io->callback = callback; io->opaque = opaque; + io->looper = (GLooper*) looper; io->wanted = 0; io->ready = 0; + socket_set_nonblock(fd); + glooper_addIo(gg, io); user->impl = io; @@ -254,6 +259,7 @@ struct GLooper { ARefSet ios[1]; /* set of all i/o waiters */ ARefSet pendingIos[1]; /* list of pending i/o waiters */ + int numActiveIos; /* number of active LoopIo objects */ IoLooper* iolooper; int running; @@ -323,6 +329,12 @@ glooper_delPendingIo(GLooper* looper, GLoopIo* io) static void glooper_modifyFd(GLooper* looper, int fd, int oldWanted, int newWanted) { + if (oldWanted == 0 && newWanted != 0) + looper->numActiveIos += 1; + + if (oldWanted != 0 && newWanted == 0) + looper->numActiveIos -= 1; + iolooper_modify(looper->iolooper, fd, oldWanted, newWanted); } @@ -339,8 +351,8 @@ glooper_forceQuit(Looper* ll) looper->running = 0; } -static void -glooper_run(Looper* ll) +static int +glooper_run(Looper* ll, Duration loop_deadline_ms) { GLooper* looper = (GLooper*) ll; IoLooper* iol = looper->iolooper; @@ -351,12 +363,21 @@ glooper_run(Looper* ll) { int ret; + /* Exit prematurely if we detect that we don't have any active timer + * and no active LoopIo + */ + if (looper->numActiveIos == 0 && looper->activeTimers == NULL) + return EWOULDBLOCK; + /* First, compute next deadline */ Duration deadline = DURATION_INFINITE; if (looper->activeTimers != NULL) deadline = looper->activeTimers->deadline; + if (deadline > loop_deadline_ms) + deadline = loop_deadline_ms; + ret = iolooper_wait_absolute(iol, deadline); if (ret < 0) { /* error, force stop ! */ break; @@ -425,7 +446,11 @@ glooper_run(Looper* ll) }); arefSet_clear(looper->pendingIos); } + + if (deadline > loop_deadline_ms) + return ETIMEDOUT; } + return 0; } static void @@ -451,6 +476,8 @@ Looper* looper_newGeneric(void) ANEW0(looper); + looper->iolooper = iolooper_new(); + looper->looper.now = glooper_now; looper->looper.timer_init = glooper_timer_init; looper->looper.io_init = glooper_io_init; diff --git a/android/looper-qemu.c b/android/looper-qemu.c index 0e55658..400f7c1 100644 --- a/android/looper-qemu.c +++ b/android/looper-qemu.c @@ -13,6 +13,7 @@ /* Implement the Looper interface on top of the QEMU main event loop */ #include <android/looper.h> +#include <android/utils/panic.h> #include "qemu-common.h" #include "qemu-timer.h" #include "qemu-char.h" @@ -370,6 +371,15 @@ qlooper_forceQuit(Looper* ll) qemu_system_shutdown_request(); } +/* The user cannot call looper_run on the core event loop, because it + * is started by qemu_main() explicitely instead, so just panic. */ +int +qlooper_run(Looper* ll, Duration deadline_ms) +{ + APANIC("Trying to run the QEMU main event loop explicitely!"); + return EINVAL; +} + static void qlooper_destroy(Looper* ll) { @@ -395,6 +405,7 @@ looper_newCore(void) looper->looper.now = qlooper_now; looper->looper.timer_init = qlooper_timer_init; looper->looper.io_init = qlooper_io_init; + looper->looper.run = qlooper_run; looper->looper.forceQuit = qlooper_forceQuit; looper->looper.destroy = qlooper_destroy; diff --git a/android/looper.h b/android/looper.h index 52a9189..d67fdad 100644 --- a/android/looper.h +++ b/android/looper.h @@ -15,6 +15,7 @@ #include <stddef.h> #include <stdint.h> #include <limits.h> +#include <android/utils/system.h> /********************************************************************** ********************************************************************** @@ -90,7 +91,7 @@ struct Looper { Duration (*now) (Looper* looper); void (*timer_init)(Looper* looper, LoopTimer* timer, LoopTimerFunc callback, void* opaque); void (*io_init) (Looper* looper, LoopIo* io, int fd, LoopIoFunc callback, void* opaque); - void (*run) (Looper* looper); + int (*run) (Looper* looper, Duration deadline_ms); void (*forceQuit) (Looper* looper); void (*destroy) (Looper* looper); }; @@ -124,7 +125,7 @@ struct LoopTimerClass { /* Initialize a LoopTimer with a callback and an 'opaque' value. * Each timer belongs to only one looper object. */ -extern __inline__ void +AINLINED void loopTimer_init(LoopTimer* timer, Looper* looper, LoopTimerFunc callback, @@ -134,7 +135,7 @@ loopTimer_init(LoopTimer* timer, } /* Finalize a LoopTimer */ -extern __inline__ void +AINLINED void loopTimer_done(LoopTimer* timer) { timer->clazz->done(timer->impl); @@ -146,7 +147,7 @@ loopTimer_done(LoopTimer* timer) * unless loopTimer_stop() is called before that, or the timer is * reprogrammed with another loopTimer_startXXX() call. */ -extern __inline__ void +AINLINED void loopTimer_startRelative(LoopTimer* timer, Duration timeout_ms) { timer->clazz->startRelative(timer->impl, timeout_ms); @@ -158,21 +159,21 @@ loopTimer_startRelative(LoopTimer* timer, Duration timeout_ms) * fire as soon as possible. Note that this can cause infinite loops * in your code if you're not careful. */ -extern __inline__ void +AINLINED void loopTimer_startAbsolute(LoopTimer* timer, Duration deadline_ms) { timer->clazz->startAbsolute(timer->impl, deadline_ms); } /* Stop a given timer */ -extern __inline__ void +AINLINED void loopTimer_stop(LoopTimer* timer) { timer->clazz->stop(timer->impl); } /* Returns true iff the timer is active / started */ -extern __inline__ int +AINLINED int loopTimer_isActive(LoopTimer* timer) { return timer->clazz->isActive(timer->impl); @@ -217,7 +218,7 @@ struct LoopIoClass { void (*done)(void* impl); }; -extern __inline__ void +AINLINED void loopIo_init(LoopIo* io, Looper* looper, int fd, LoopIoFunc callback, void* opaque) { looper->io_init(looper, io, fd, callback, opaque); @@ -225,7 +226,7 @@ loopIo_init(LoopIo* io, Looper* looper, int fd, LoopIoFunc callback, void* opaqu } /* Note: This does not close the file descriptor! */ -extern __inline__ void +AINLINED void loopIo_done(LoopIo* io) { io->clazz->done(io->impl); @@ -234,22 +235,22 @@ loopIo_done(LoopIo* io) /* The following functions are used to indicate whether you want the callback * to be fired when there is data to be read or when the file is ready to * be written to. */ -extern __inline__ void +AINLINED void loopIo_wantRead(LoopIo* io) { io->clazz->wantRead(io->impl); } -extern __inline__ void +AINLINED void loopIo_wantWrite(LoopIo* io) { io->clazz->wantWrite(io->impl); } -extern __inline__ void +AINLINED void loopIo_dontWantRead(LoopIo* io) { io->clazz->dontWantRead(io->impl); } -extern __inline__ void +AINLINED void loopIo_dontWantWrite(LoopIo* io) { io->clazz->dontWantWrite(io->impl); @@ -263,16 +264,58 @@ loopIo_dontWantWrite(LoopIo* io) ********************************************************************** **********************************************************************/ +AINLINED Duration +looper_now(Looper* looper) +{ + return looper->now(looper); +} /* Run the event loop, until looper_forceQuit() is called, or there is no * more registered watchers for events/timers in the looper. + * + * The value returned indicates the reason: + * 0 -> normal exit through looper_forceQuit() + * EWOULDBLOCK -> there are not more watchers registered (the looper + * would loop infinitely) */ -extern __inline__ void +AINLINED void looper_run(Looper* looper) { - looper->run(looper); + (void) looper->run(looper, DURATION_INFINITE); } -extern __inline__ void +/* A variant of looper_run() that allows to run the event loop only + * until a certain timeout in milliseconds has passed. + * + * Returns the reason why the looper stopped: + * 0 -> normal exit through looper_forceQuit() + * EWOULDBLOCK -> there are not more watchers registered (the looper + * would loop infinitely) + * ETIMEDOUT -> timeout reached + * + */ +AINLINED int +looper_runWithTimeout(Looper* looper, Duration timeout_ms) +{ + if (timeout_ms != DURATION_INFINITE) + timeout_ms += looper_now(looper); + + return looper->run(looper, timeout_ms); +} + +/* Another variant of looper_run() that takes a deadline instead of a + * timeout. Same return values than looper_runWithTimeout() + */ +AINLINED int +looper_runWithDeadline(Looper* looper, Duration deadline_ms) +{ + return looper->run(looper, deadline_ms); +} + +/* Call this function from within the event loop to force it to quit + * as soon as possible. looper_run() / _runWithTimeout() / _runWithDeadline() + * will then return 0. + */ +AINLINED void looper_forceQuit(Looper* looper) { looper->forceQuit(looper); @@ -284,7 +327,7 @@ looper_forceQuit(Looper* looper) * NOTE: This assumes that the user has destroyed all its * timers and ios properly */ -extern __inline__ void +AINLINED void looper_free(Looper* looper) { if (looper) diff --git a/iolooper-select.c b/iolooper-select.c index dc5257c..955204d 100644 --- a/iolooper-select.c +++ b/iolooper-select.c @@ -67,15 +67,15 @@ iolooper_modify( IoLooper* iol, int fd, int oldflags, int newflags ) if ((changed & IOLOOPER_READ) != 0) { if ((newflags & IOLOOPER_READ) != 0) - FD_SET(fd, iol->reads); + iolooper_add_read(iol, fd); else - FD_CLR(fd, iol->reads); + iolooper_del_read(iol, fd); } if ((changed & IOLOOPER_WRITE) != 0) { if ((newflags & IOLOOPER_WRITE) != 0) - FD_SET(fd, iol->writes); + iolooper_add_write(iol, fd); else - FD_CLR(fd, iol->writes); + iolooper_del_write(iol, fd); } } @@ -230,5 +230,11 @@ int iolooper_wait_absolute(IoLooper* iol, int64_t deadline) { int64_t timeout = deadline - iolooper_now(); - return (timeout >= 0) ? iolooper_wait(iol, timeout) : 0; + + /* If the deadline has passed, set the timeout to 0, this allows us + * to poll the file descriptor nonetheless */ + if (timeout < 0) + timeout = 0; + + return iolooper_wait(iol, timeout); } |