blob: d22a798a438b404420647eee30842011a952efe1 [file] [log] [blame]
/* 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.
*/
#pragma once
#include "android/utils/compiler.h"
#include "android/utils/stream.h"
#include "android/utils/system.h"
#include <stddef.h>
#include <stdint.h>
#include <limits.h>
ANDROID_BEGIN_HEADER
/* stdint.h will not define necessary macros in some c++ compiler
* implementations without this macro definition.
*/
#if defined(__cplusplus) && !defined(__STDC_LIMIT_MACROS)
#error "This header requires you to define __STDC_LIMIT_MACROS."
#endif
/**********************************************************************
**********************************************************************
*****
***** T I M E R E P R E S E N T A T I O N
*****
**********************************************************************
**********************************************************************/
/* A Duration represents a duration in milliseconds */
typedef int64_t Duration;
/* High-precision duration, in nanoseconds */
typedef uint64_t DurationNs;
/* A special Duration value used to mean "infinite" */
#define DURATION_INFINITE ((Duration)INT64_MAX)
// Type of the clock used in a Looper object
// LOOPER_CLOCK_REALTIME - realtime monotonic host clock
// LOOPER_CLOCK_VIRTUAL - virtual machine guest time, stops when guest is
// suspended
// LOOPER_CLOCK_HOST - host time, mimics the current time set in the OS, so
// is may go back when OS time is set back
//
// Note: the only time which is always supported is LOOPER_CLOCK_HOST;
// other types may be not implemented by different times and fall back
// to LOOPER_CLOCK_HOST
typedef enum {
LOOPER_CLOCK_REALTIME,
LOOPER_CLOCK_VIRTUAL,
LOOPER_CLOCK_HOST
} LooperClockType;
/**********************************************************************
**********************************************************************
*****
***** 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_getForThread() instead. Its implementation relies on top of
* the QEMU event loop instead.
*/
typedef struct Looper Looper;
/* Return the Looper instance for the current thread. If none exists,
* create a new one with looper_newGeneric().
* IMPORTANT: never call looper_free() on the result of this function.
*/
Looper* looper_getForThread(void);
/* Set the current thread's Looper instance. This is only useful if you
* have a Looper implementation based on a foreign main loop. */
void looper_setForThread(Looper* looper);
// This version of the set function passes the looper ownership - so it is
// deallocated on thread exit.
void looper_setForThreadToOwn(Looper* looper);
/* Create a new generic looper that can be used in any context / thread. */
Looper* looper_newGeneric(void);
typedef struct LoopTimer LoopTimer;
typedef void (*LoopTimerFunc)(void* opaque, LoopTimer* timer);
typedef struct LoopIo LoopIo;
typedef void (*LoopIoFunc)(void* opaque, int fd, unsigned events);
/**********************************************************************
**********************************************************************
*****
***** T I M E R S
*****
**********************************************************************
**********************************************************************/
/* Initialize a LoopTimer with a callback and an 'opaque' value.
* Each timer belongs to only one looper object.
*/
LoopTimer* loopTimer_new(Looper* looper,
LoopTimerFunc callback,
void* opaque);
LoopTimer* loopTimer_newWithClock(Looper* looper,
LoopTimerFunc callback,
void* opaque,
LooperClockType clock);
/* Finalize a LoopTimer */
void loopTimer_free(LoopTimer* timer);
/* 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.
*/
void loopTimer_startRelative(LoopTimer* timer, Duration 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.
*/
void loopTimer_startAbsolute(LoopTimer* timer, Duration deadline_ms);
/* Stop a given timer */
void loopTimer_stop(LoopTimer* timer);
/* Returns true iff the timer is active / started */
int loopTimer_isActive(LoopTimer* timer);
/**********************************************************************
**********************************************************************
*****
***** F I L E D E S C R I P T O R S
*****
**********************************************************************
**********************************************************************/
/* 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),
};
LoopIo* loopIo_new(Looper* looper,
int fd,
LoopIoFunc callback,
void* opaque);
/* Note: This does not close the file descriptor! */
void loopIo_free(LoopIo* io);
int loopIo_fd(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. */
void loopIo_wantRead(LoopIo* io);
void loopIo_wantWrite(LoopIo* io);
void loopIo_dontWantRead(LoopIo* io);
void loopIo_dontWantWrite(LoopIo* io);
unsigned loopIo_poll(LoopIo* io);
/**********************************************************************
**********************************************************************
*****
***** L O O P E R
*****
**********************************************************************
**********************************************************************/
/* Return the current looper time in milliseconds. This can be used to
* compute deadlines for looper_runWithDeadline(). */
Duration looper_now(Looper* looper);
Duration looper_nowWithClock(Looper* looper, LooperClockType clock);
/* Current time in nanoseconds */
DurationNs looper_nowNs(Looper* looper);
DurationNs looper_nowNsWithClock(Looper* looper, LooperClockType clock);
/* Run the event loop, until looper_forceQuit() is called, or there is no
* more registered watchers for events/timers in the looper, or a certain
* deadline expires.
*
* |deadline_ms| is a deadline in milliseconds.
*
* The value returned indicates the reason:
* 0 -> normal exit through looper_forceQuit()
* EWOULDBLOCK -> there are not more watchers registered (the looper
* would loop infinitely)
* ETIMEDOUT -> deadline expired.
*/
int looper_runWithDeadline(Looper* looper, Duration deadline_ms);
/* Run the event loop, until looper_forceQuit() is called, or there is no
* more registered watchers for events/timers in the looper.
*/
AINLINED void looper_run(Looper* looper) {
(void) looper_runWithDeadline(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_runWithDeadline(looper, timeout_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.
*/
void looper_forceQuit(Looper* 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
*/
void looper_free(Looper* looper);
// Serialization/deserialization support
void stream_put_timer(Stream* stream, LoopTimer* timer);
void stream_get_timer(Stream* stream, LoopTimer* timer);
/* */
ANDROID_END_HEADER