| /* Copyright (C) 2010 The Android Open Source Project |
| ** |
| ** This software is licensed under the terms of the GNU General Public |
| ** License version 2, as published by the Free Software Foundation, and |
| ** may be copied, distributed, and modified under those terms. |
| ** |
| ** This program is distributed in the hope that it will be useful, |
| ** but WITHOUT ANY WARRANTY; without even the implied warranty of |
| ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| ** GNU General Public License for more details. |
| */ |
| #ifndef ANDROID_LOOPER_H |
| #define ANDROID_LOOPER_H |
| |
| #include <stddef.h> |
| #include <stdint.h> |
| #include <limits.h> |
| #include <android/utils/system.h> |
| |
| /********************************************************************** |
| ********************************************************************** |
| ***** |
| ***** T I M E R E P R E S E N T A T I O N |
| ***** |
| ********************************************************************** |
| **********************************************************************/ |
| |
| /* An Duration represents a duration in milliseconds */ |
| typedef int64_t Duration; |
| |
| /* A special Duration value used to mean "infinite" */ |
| #define DURATION_INFINITE ((Duration)INT64_MAX) |
| |
| /********************************************************************** |
| ********************************************************************** |
| ***** |
| ***** E V E N T L O O P O B J E C T S |
| ***** |
| ********************************************************************** |
| **********************************************************************/ |
| |
| |
| /* A Looper is an abstraction for an event loop, which can |
| * be implemented in different ways. For example, the UI program may |
| * want to implement a custom event loop on top of the SDL event queue, |
| * while the QEMU core would implement it on top of QEMU's internal |
| * main loop which works differently. |
| * |
| * Once you have a Looper pointer, you can register "watchers" that |
| * will trigger callbacks whenever certain events occur. Supported event |
| * types are: |
| * |
| * - timer expiration |
| * - i/o file descriptor input/output |
| * |
| * See the relevant documentation for these below. |
| * |
| * Once you have registered one or more watchers, you can call looper_run() |
| * which will run the event loop until looper_forceQuit() is called from a |
| * callback, or no more watchers are registered. |
| * |
| * You can register/unregister watchers from a callback, or call various |
| * Looper methods from them (e.g. looper_now(), looper_forceQuit(), etc..) |
| * |
| * You can create a new Looper by calling looper_newGeneric(). This provides |
| * a default implementation that can be used in all threads. |
| * |
| * For the QEMU core, you can grab a Looper pointer by calling |
| * looper_newCore() instead. Its implementation relies on top of |
| * the QEMU event loop instead. |
| */ |
| typedef struct Looper Looper; |
| |
| /* Create a new generic looper that can be used in any context / thread. */ |
| Looper* looper_newGeneric(void); |
| |
| /* Create a new looper which is implemented on top of the QEMU main event |
| * loop. You should only use this when implementing the emulator UI and Core |
| * features in a single program executable. |
| */ |
| Looper* looper_newCore(void); |
| |
| |
| typedef struct LoopTimer LoopTimer; |
| typedef void (*LoopTimerFunc)(void* opaque); |
| |
| typedef struct LoopIo LoopIo; |
| typedef void (*LoopIoFunc)(void* opaque, int fd, unsigned events); |
| |
| 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); |
| int (*run) (Looper* looper, Duration deadline_ms); |
| void (*forceQuit) (Looper* looper); |
| void (*destroy) (Looper* looper); |
| }; |
| |
| |
| |
| /********************************************************************** |
| ********************************************************************** |
| ***** |
| ***** T I M E R S |
| ***** |
| ********************************************************************** |
| **********************************************************************/ |
| |
| |
| typedef struct LoopTimerClass LoopTimerClass; |
| |
| struct LoopTimer { |
| LoopTimerClass* clazz; |
| void* impl; |
| }; |
| |
| struct LoopTimerClass { |
| void (*startRelative)(void* impl, Duration timeout_ms); |
| void (*startAbsolute)(void* impl, Duration deadline_ms); |
| void (*stop) (void* impl); |
| int (*isActive) (void* impl); |
| void (*done) (void* impl); |
| }; |
| |
| /* Initialize a LoopTimer with a callback and an 'opaque' value. |
| * Each timer belongs to only one looper object. |
| */ |
| AINLINED void |
| loopTimer_init(LoopTimer* timer, |
| Looper* looper, |
| LoopTimerFunc callback, |
| void* opaque) |
| { |
| looper->timer_init(looper, timer, callback, opaque); |
| } |
| |
| /* Finalize a LoopTimer */ |
| AINLINED void |
| loopTimer_done(LoopTimer* timer) |
| { |
| timer->clazz->done(timer->impl); |
| timer->clazz = NULL; |
| timer->impl = NULL; |
| } |
| |
| /* Start a timer, i.e. arm it to expire in 'timeout_ms' milliseconds, |
| * unless loopTimer_stop() is called before that, or the timer is |
| * reprogrammed with another loopTimer_startXXX() call. |
| */ |
| AINLINED void |
| loopTimer_startRelative(LoopTimer* timer, Duration timeout_ms) |
| { |
| timer->clazz->startRelative(timer->impl, timeout_ms); |
| } |
| |
| /* A variant of loopTimer_startRelative that fires on a given deadline |
| * in milliseconds instead. If the deadline already passed, the timer is |
| * automatically appended to the list of pending event watchers and will |
| * fire as soon as possible. Note that this can cause infinite loops |
| * in your code if you're not careful. |
| */ |
| AINLINED void |
| loopTimer_startAbsolute(LoopTimer* timer, Duration deadline_ms) |
| { |
| timer->clazz->startAbsolute(timer->impl, deadline_ms); |
| } |
| |
| /* Stop a given timer */ |
| AINLINED void |
| loopTimer_stop(LoopTimer* timer) |
| { |
| timer->clazz->stop(timer->impl); |
| } |
| |
| /* Returns true iff the timer is active / started */ |
| AINLINED int |
| loopTimer_isActive(LoopTimer* timer) |
| { |
| return timer->clazz->isActive(timer->impl); |
| } |
| |
| /********************************************************************** |
| ********************************************************************** |
| ***** |
| ***** F I L E D E S C R I P T O R S |
| ***** |
| ********************************************************************** |
| **********************************************************************/ |
| |
| typedef struct LoopIoClass LoopIoClass; |
| |
| struct LoopIo { |
| LoopIoClass* clazz; |
| void* impl; |
| int fd; |
| }; |
| |
| /* Bitmasks about i/o events. Note that errors (e.g. network disconnections) |
| * are mapped to both read and write events. The idea is that a read() or |
| * write() will return 0 or even -1 on non-blocking file descriptors in this |
| * case. |
| * |
| * You can receive several events at the same time on a single LoopIo |
| * |
| * Socket connect()s are mapped to LOOP_IO_WRITE events. |
| * Socket accept()s are mapped to LOOP_IO_READ events. |
| */ |
| enum { |
| LOOP_IO_READ = (1 << 0), |
| LOOP_IO_WRITE = (1 << 1), |
| }; |
| |
| struct LoopIoClass { |
| void (*wantRead)(void* impl); |
| void (*wantWrite)(void* impl); |
| void (*dontWantRead)(void* impl); |
| void (*dontWantWrite)(void* impl); |
| unsigned (*poll)(void* impl); |
| void (*done)(void* impl); |
| }; |
| |
| AINLINED void |
| loopIo_init(LoopIo* io, Looper* looper, int fd, LoopIoFunc callback, void* opaque) |
| { |
| looper->io_init(looper, io, fd, callback, opaque); |
| io->fd = fd; |
| } |
| |
| /* Note: This does not close the file descriptor! */ |
| AINLINED void |
| loopIo_done(LoopIo* io) |
| { |
| io->clazz->done(io->impl); |
| } |
| |
| /* 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. */ |
| AINLINED void |
| loopIo_wantRead(LoopIo* io) |
| { |
| io->clazz->wantRead(io->impl); |
| } |
| AINLINED void |
| loopIo_wantWrite(LoopIo* io) |
| { |
| io->clazz->wantWrite(io->impl); |
| } |
| AINLINED void |
| loopIo_dontWantRead(LoopIo* io) |
| { |
| io->clazz->dontWantRead(io->impl); |
| } |
| AINLINED void |
| loopIo_dontWantWrite(LoopIo* io) |
| { |
| io->clazz->dontWantWrite(io->impl); |
| } |
| AINLINED unsigned |
| loopIo_poll(LoopIo* io) |
| { |
| return io->clazz->poll(io->impl); |
| } |
| |
| /********************************************************************** |
| ********************************************************************** |
| ***** |
| ***** L O O P E R |
| ***** |
| ********************************************************************** |
| **********************************************************************/ |
| |
| 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) |
| */ |
| AINLINED void |
| looper_run(Looper* looper) |
| { |
| (void) looper->run(looper, DURATION_INFINITE); |
| } |
| |
| /* 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); |
| } |
| |
| /* Destroy a given looper object. Only works for those created |
| * with looper_new(). Cannot be called within looper_run()!! |
| * |
| * NOTE: This assumes that the user has destroyed all its |
| * timers and ios properly |
| */ |
| AINLINED void |
| looper_free(Looper* looper) |
| { |
| if (looper) |
| looper->destroy(looper); |
| } |
| |
| /* */ |
| |
| #endif /* ANDROID_LOOPER_H */ |