aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid 'Digit' Turner <digit@android.com>2010-11-18 16:10:45 +0100
committerDavid 'Digit' Turner <digit@android.com>2010-11-19 14:51:17 +0100
commit1bb627cd086588d3f9650fac04f4034961caf9f1 (patch)
tree2f12b3074cd6314f9556d21f074508d66c03d971
parent3aa86ac4b79c71e443d3010a84bed1da27f48880 (diff)
downloadexternal_qemu-1bb627cd086588d3f9650fac04f4034961caf9f1.zip
external_qemu-1bb627cd086588d3f9650fac04f4034961caf9f1.tar.gz
external_qemu-1bb627cd086588d3f9650fac04f4034961caf9f1.tar.bz2
Fix generic looper implementation
+ allow looper_run() to return a value that indicates why it exited. + add looper_runWithDeadline() and looper_runWithTimeout() in the case where you want to run only for a limited time. looper_runWithTimeout(looper,0) can be used to poll the event state and return asap after firing all the callbacks. + fix iolooper_modify() Change-Id: Iba3b0385a7fd8d90f4f3334ebf313e79267f7b3d
-rw-r--r--android/looper-generic.c31
-rw-r--r--android/looper-qemu.c11
-rw-r--r--android/looper.h77
-rw-r--r--iolooper-select.c16
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);
}