[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [RFC] [PATCHv8 07/30] aio / timers: Split QEMUClock int
From: |
Paolo Bonzini |
Subject: |
Re: [Qemu-devel] [RFC] [PATCHv8 07/30] aio / timers: Split QEMUClock into QEMUClock and QEMUTimerList |
Date: |
Fri, 09 Aug 2013 12:03:07 +0200 |
User-agent: |
Mozilla/5.0 (X11; Linux x86_64; rv:17.0) Gecko/20130625 Thunderbird/17.0.7 |
Il 08/08/2013 23:42, Alex Bligh ha scritto:
> Split QEMUClock into QEMUClock and QEMUTimerList so that we can
> have more than one QEMUTimerList associated with the same clock.
>
> Introduce a main_loop_timerlist concept and make existing
> qemu_clock_* calls that actually should operate on a QEMUTimerList
> call the relevant QEMUTimerList implementations, using the clock's
> default timerlist. This vastly reduces the invasiveness of this
> change and means the API stays constant for existing users.
>
> Introduce a list of QEMUTimerLists associated with each clock
> so that reenabling the clock can cause all the notifiers
> to be called. Note the code to do the notifications is added
> in a later patch.
>
> Switch QEMUClockType to an enum. Remove global variables vm_clock,
> host_clock and rt_clock and add compatibility defines. Do not
> fix qemu_next_alarm_deadline as it's going to be deleted.
>
> Add qemu_clock_use_for_deadline to indicate whether a particular
> clock should be used for deadline calculations. When use_icount
> is true, vm_clock should not be used for deadline calculations
> as it does not contain a nanosecond count. Instead, icount
> timeouts come from the execution thread doing aio_notify or
> qemu_notify as appropriate. This function is used in the next
> patch.
>
> Signed-off-by: Alex Bligh <address@hidden>
> ---
> include/qemu/timer.h | 406
> +++++++++++++++++++++++++++++++++++++++++++++++---
> qemu-timer.c | 200 +++++++++++++++++++------
> 2 files changed, 536 insertions(+), 70 deletions(-)
>
> diff --git a/include/qemu/timer.h b/include/qemu/timer.h
> index c270144..6c2bf6c 100644
> --- a/include/qemu/timer.h
> +++ b/include/qemu/timer.h
> @@ -11,34 +11,75 @@
> #define SCALE_US 1000
> #define SCALE_NS 1
>
> -#define QEMU_CLOCK_REALTIME 0
> -#define QEMU_CLOCK_VIRTUAL 1
> -#define QEMU_CLOCK_HOST 2
> +/**
> + * QEMUClockType:
> + *
> + * The following clock types are available:
> + *
> + * @QEMU_CLOCK_REALTIME: Real time clock
> + *
> + * The real time clock should be used only for stuff which does not
> + * change the virtual machine state, as it is run even if the virtual
> + * machine is stopped. The real time clock has a frequency of 1000
> + * Hz.
> + *
> + * Formerly rt_clock
> + *
> + * @QEMU_CLOCK_VIRTUAL: virtual clock
> + *
> + * The virtual clock is only run during the emulation. It is stopped
> + * when the virtual machine is stopped. Virtual timers use a high
> + * precision clock, usually cpu cycles (use ticks_per_sec).
> + *
> + * Formerly vm_clock
> + *
> + * @QEMU_CLOCK_HOST: host clock
> + *
> + * The host clock should be use for device models that emulate accurate
> + * real time sources. It will continue to run when the virtual machine
> + * is suspended, and it will reflect system time changes the host may
> + * undergo (e.g. due to NTP). The host clock has the same precision as
> + * the virtual clock.
> + *
> + * Formerly host_clock
> + */
> +
> +typedef enum {
> + QEMU_CLOCK_REALTIME = 0,
> + QEMU_CLOCK_VIRTUAL = 1,
> + QEMU_CLOCK_HOST = 2,
> + QEMU_CLOCK_MAX
> +} QEMUClockType;
>
> typedef struct QEMUClock QEMUClock;
> +typedef struct QEMUTimerList QEMUTimerList;
> typedef void QEMUTimerCB(void *opaque);
>
> -/* The real time clock should be used only for stuff which does not
> - change the virtual machine state, as it is run even if the virtual
> - machine is stopped. The real time clock has a frequency of 1000
> - Hz. */
> -extern QEMUClock *rt_clock;
> +extern QEMUClock *qemu_clocks[QEMU_CLOCK_MAX];
>
> -/* The virtual clock is only run during the emulation. It is stopped
> - when the virtual machine is stopped. Virtual timers use a high
> - precision clock, usually cpu cycles (use ticks_per_sec). */
> -extern QEMUClock *vm_clock;
> +/**
> + * qemu_clock_ptr:
> + * @type: type of clock
> + *
> + * Translate a clock type into a pointer to QEMUClock object.
> + *
> + * Returns: a pointer to the QEMUClock object
> + */
> +static inline QEMUClock *qemu_clock_ptr(QEMUClockType type)
> +{
> + return qemu_clocks[type];
> +}
>
> -/* The host clock should be use for device models that emulate accurate
> - real time sources. It will continue to run when the virtual machine
> - is suspended, and it will reflect system time changes the host may
> - undergo (e.g. due to NTP). The host clock has the same precision as
> - the virtual clock. */
> -extern QEMUClock *host_clock;
> +/* These three clocks are maintained here with separate variable
> + * names for compatibility only.
> + */
> +#define rt_clock (qemu_clock_ptr(QEMU_CLOCK_REALTIME))
> +#define vm_clock (qemu_clock_ptr(QEMU_CLOCK_VIRTUAL))
> +#define host_clock (qemu_clock_ptr(QEMU_CLOCK_HOST))
>
> int64_t qemu_get_clock_ns(QEMUClock *clock);
> -int64_t qemu_clock_has_timers(QEMUClock *clock);
> -int64_t qemu_clock_expired(QEMUClock *clock);
> +bool qemu_clock_has_timers(QEMUClock *clock);
> +bool qemu_clock_expired(QEMUClock *clock);
> int64_t qemu_clock_deadline(QEMUClock *clock);
>
> /**
> @@ -53,6 +94,124 @@ int64_t qemu_clock_deadline(QEMUClock *clock);
> int64_t qemu_clock_deadline_ns(QEMUClock *clock);
>
> /**
> + * qemu_clock_use_for_deadline:
> + * @clock: the clock to operate on
> + *
> + * Determine whether a clock should be used for deadline
> + * calculations. Some clocks, for instance vm_clock with
> + * use_icount set, do not count in nanoseconds. Such clocks
> + * are not used for deadline calculations, and are presumed
> + * to interrupt any poll using qemu_notify/aio_notify
> + * etc.
> + *
> + * Returns: true if the clock runs in nanoseconds and
> + * should be used for a deadline.
> + */
> +bool qemu_clock_use_for_deadline(QEMUClock *clock);
> +
> +/**
> + * qemu_clock_get_main_loop_timerlist:
> + * @clock: the clock to operate on
> + *
> + * Return the default timer list assocatiated with a clock.
> + *
> + * Returns: the default timer list
> + */
> +QEMUTimerList *qemu_clock_get_main_loop_timerlist(QEMUClock *clock);
> +
> +/**
> + * timerlist_new:
> + * @type: the clock type to associate with the timerlist
> + *
> + * Create a new timerlist associated with the clock of
> + * type @type.
> + *
> + * Returns: a pointer to the QEMUTimerList created
> + */
> +QEMUTimerList *timerlist_new(QEMUClockType type);
> +
> +/**
> + * timerlist_free:
> + * @timer_list: the timer list to free
> + *
> + * Frees a timer_list. It must have no active timers.
> + */
> +void timerlist_free(QEMUTimerList *timer_list);
> +
> +/**
> + * timerlist_has_timers:
> + * @timer_list: the timer list to operate on
> + *
> + * Determine whether a timer list has active timers
> + *
> + * Returns: true if the timer list has timers.
> + */
> +bool timerlist_has_timers(QEMUTimerList *timer_list);
> +
> +/**
> + * timerlist_expired:
> + * @timer_list: the timer list to operate on
> + *
> + * Determine whether a timer list has any timers which
> + * are expired.
> + *
> + * Returns: true if the timer list has timers which
> + * have expired.
> + */
> +bool timerlist_expired(QEMUTimerList *timer_list);
> +
> +/**
> + * timerlist_deadline:
> + * @timer_list: the timer list to operate on
> + *
> + * Determine the deadline for a timer_list. This is
> + * a legacy function which returns INT32_MAX if the
> + * timer list has no timers or if the earliest timer
> + * expires later than INT32_MAX nanoseconds away.
> + *
> + * Returns: the number of nanoseconds until the earliest
> + * timer expires or INT32_MAX in the situations listed
> + * above
> + */
> +int64_t timerlist_deadline(QEMUTimerList *timer_list);
> +
> +/**
> + * timerlist_deadline_ns:
> + * @timer_list: the timer list to operate on
> + *
> + * Determine the deadline for a timer_list, i.e.
> + * the number of nanoseconds until the first timer
> + * expires. Return -1 if there are no timers.
> + *
> + * Returns: the number of nanoseconds until the earliest
> + * timer expires -1 if none
> + */
> +int64_t timerlist_deadline_ns(QEMUTimerList *timer_list);
> +
> +/**
> + * timerlist_getclock:
> + * @timer_list: the timer list to operate on
> + *
> + * Read the clock value associated with a timer list.
> + * The clock value is normally in nanoseconds, but may
> + * not be in some instances (e.g. vm_clock with use_icount).
> + *
> + * Returns: the value of the clock associated with the
> + * timer list.
> + */
> +QEMUClock *timerlist_get_clock(QEMUTimerList *timer_list);
> +
> +/**
> + * timerlist_run_timers:
> + * @timer_list: the timer list to use
> + *
> + * Call all expired timers associated with the timer list.
> + *
> + * Returns: true if any timer expired
> + */
> +bool timerlist_run_timers(QEMUTimerList *timer_list);
> +
> +/**
> * qemu_timeout_ns_to_ms:
> * @ns: nanosecond timeout value
> *
> @@ -84,6 +243,21 @@ void qemu_unregister_clock_reset_notifier(QEMUClock
> *clock,
>
> QEMUTimer *qemu_new_timer(QEMUClock *clock, int scale,
> QEMUTimerCB *cb, void *opaque);
> +
> +/**
> + * timer_new:
> + * @timer_list: the timer list to attach the timer to
> + * @scale: the scale value for the tiemr
> + * @cb: the callback to be called when the timer expires
> + * @opaque: the opaque pointer to be passed to the callback
> + *
> + * Creeate a new timer and associate it with @timer_list.
> + *
> + * Returns: a pointer to the timer
> + */
> +QEMUTimer *timer_new(QEMUTimerList *timer_list, int scale,
> + QEMUTimerCB *cb, void *opaque);
> +
> void qemu_free_timer(QEMUTimer *ts);
> void qemu_del_timer(QEMUTimer *ts);
> void qemu_mod_timer_ns(QEMUTimer *ts, int64_t expire_time);
> @@ -92,11 +266,101 @@ bool qemu_timer_pending(QEMUTimer *ts);
> bool qemu_timer_expired(QEMUTimer *timer_head, int64_t current_time);
> uint64_t qemu_timer_expire_time_ns(QEMUTimer *ts);
>
> +/* New format calling conventions for timers */
> +
> +/**
> + * timer_free:
> + * @ts: the timer
> + *
> + * Free a timer (it must not be on the active list)
> + */
> +static inline void timer_free(QEMUTimer *ts)
> +{
> + qemu_free_timer(ts);
> +}
If these functions have the same implementation, independent of ts's
timerlist, let's just keep the qemu_*_timer names.
Paolo
> +/**
> + * timer_del:
> + * @ts: the timer
> + *
> + * Delete a timer from the active list.
> + */
> +static inline void timer_del(QEMUTimer *ts)
> +{
> + qemu_del_timer(ts);
> +}
> +
> +/**
> + * timer_mod_ns:
> + * @ts: the timer
> + * @expire_time: the expiry time in nanoseconds
> + *
> + * Modify a timer to expire at @expire_time
> + */
> +static inline void timer_mod_ns(QEMUTimer *ts, int64_t expire_time)
> +{
> + qemu_mod_timer_ns(ts, expire_time);
> +}
> +
> +/**
> + * timer_mod:
> + * @ts: the timer
> + * @expire_time: the expire time in the units associated with the timer
> + *
> + * Modify a timer to expiry at @expire_time, taking into
> + * account the scale associated with the timer.
> + */
> +static inline void timer_mod(QEMUTimer *ts, int64_t expire_timer)
> +{
> + qemu_mod_timer(ts, expire_timer);
> +}
> +
> +/**
> + * timer_pending:
> + * @ts: the timer
> + *
> + * Determines whether a timer is pending (i.e. is on the
> + * active list of timers, whether or not it has not yet expired).
> + *
> + * Returns: true if the timer is pending
> + */
> +static inline bool timer_pending(QEMUTimer *ts)
> +{
> + return qemu_timer_pending(ts);
> +}
> +
> +/**
> + * timer_expired:
> + * @ts: the timer
> + *
> + * Determines whether a timer has expired.
> + *
> + * Returns: true if the timer has expired
> + */
> +static inline bool timer_expired(QEMUTimer *timer_head, int64_t current_time)
> +{
> + return qemu_timer_expired(timer_head, current_time);
> +}
> +
> +/**
> + * timer_expire_time_ns:
> + * @ts: the timer
> + *
> + * Determine the expiry time of a timer
> + *
> + * Returns: the expiry time in nanoseconds
> + */
> +static inline uint64_t timer_expire_time_ns(QEMUTimer *ts)
> +{
> + return qemu_timer_expire_time_ns(ts);
> +}
> +
> /**
> * qemu_run_timers:
> * @clock: clock on which to operate
> *
> - * Run all the timers associated with a clock.
> + * Run all the timers associated with the default timer list
> + * of a clock.
> *
> * Returns: true if any timer ran.
> */
> @@ -105,7 +369,8 @@ bool qemu_run_timers(QEMUClock *clock);
> /**
> * qemu_run_all_timers:
> *
> - * Run all the timers associated with every clock.
> + * Run all the timers associated with the default timer list
> + * of every clock.
> *
> * Returns: true if any timer ran.
> */
> @@ -138,18 +403,113 @@ static inline int64_t qemu_soonest_timeout(int64_t
> timeout1, int64_t timeout2)
> return ((uint64_t) timeout1 < (uint64_t) timeout2) ? timeout1 : timeout2;
> }
>
> +/**
> + * qemu_new_timer_ns:
> + * @clock: the clock to associate with the timer
> + * @callback: the callback to call when the timer expires
> + * @opaque: the opaque pointer to pass to the callback
> + *
> + * Create a new timer with nanosecond scale on the default timer list
> + * associated with the clock.
> + *
> + * Returns: a pointer to the newly created timer
> + */
> static inline QEMUTimer *qemu_new_timer_ns(QEMUClock *clock, QEMUTimerCB *cb,
> void *opaque)
> {
> return qemu_new_timer(clock, SCALE_NS, cb, opaque);
> }
>
> -static inline QEMUTimer *qemu_new_timer_ms(QEMUClock *clock, QEMUTimerCB *cb,
> +/**
> + * timer_new_ns:
> + * @timer_list: the timer list to associate with the timer
> + * @callback: the callback to call when the timer expires
> + * @opaque: the opaque pointer to pass to the callback
> + *
> + * Create a new timer with nanosecond scale on the timer list
> + * specified.
> + *
> + * Returns: a pointer to the newly created timer
> + */
> +static inline QEMUTimer *timer_new_ns(QEMUTimerList *timer_list,
> + QEMUTimerCB *cb,
> + void *opaque)
> +{
> + return timer_new(timer_list, SCALE_NS, cb, opaque);
> +}
> +
> +/**
> + * qemu_new_timer_us:
> + * @clock: the clock to associate with the timer
> + * @callback: the callback to call when the timer expires
> + * @opaque: the opaque pointer to pass to the callback
> + *
> + * Create a new timer with microsecond scale on the default timer list
> + * associated with the clock.
> + *
> + * Returns: a pointer to the newly created timer
> + */
> +static inline QEMUTimer *qemu_new_timer_us(QEMUClock *clock,
> + QEMUTimerCB *cb,
> + void *opaque)
> +{
> + return qemu_new_timer(clock, SCALE_US, cb, opaque);
> +}
> +
> +/**
> + * timer_new_us:
> + * @timer_list: the timer list to associate with the timer
> + * @callback: the callback to call when the timer expires
> + * @opaque: the opaque pointer to pass to the callback
> + *
> + * Create a new timer with microsecond scale on the timer list
> + * specified.
> + *
> + * Returns: a pointer to the newly created timer
> + */
> +static inline QEMUTimer *timer_new_us(QEMUTimerList *timer_list,
> + QEMUTimerCB *cb,
> + void *opaque)
> +{
> + return timer_new(timer_list, SCALE_US, cb, opaque);
> +}
> +
> +/**
> + * qemu_new_timer_ms:
> + * @clock: the clock to associate with the timer
> + * @callback: the callback to call when the timer expires
> + * @opaque: the opaque pointer to pass to the callback
> + *
> + * Create a new timer with millisecond scale on the default timer list
> + * associated with the clock.
> + *
> + * Returns: a pointer to the newly created timer
> + */
> +static inline QEMUTimer *qemu_new_timer_ms(QEMUClock *clock,
> + QEMUTimerCB *cb,
> void *opaque)
> {
> return qemu_new_timer(clock, SCALE_MS, cb, opaque);
> }
>
> +/**
> + * timer_new_ms:
> + * @timer_list: the timer list to associate with the timer
> + * @callback: the callback to call when the timer expires
> + * @opaque: the opaque pointer to pass to the callback
> + *
> + * Create a new timer with millisecond scale on the timer list
> + * specified.
> + *
> + * Returns: a pointer to the newly created timer
> + */
> +static inline QEMUTimer *timer_new_ms(QEMUTimerList *timer_list,
> + QEMUTimerCB *cb,
> + void *opaque)
> +{
> + return timer_new(timer_list, SCALE_MS, cb, opaque);
> +}
> +
> static inline int64_t qemu_get_clock_ms(QEMUClock *clock)
> {
> return qemu_get_clock_ns(clock) / SCALE_MS;
> diff --git a/qemu-timer.c b/qemu-timer.c
> index c0aa58a..1a0a4b1 100644
> --- a/qemu-timer.c
> +++ b/qemu-timer.c
> @@ -49,18 +49,34 @@
> /* timers */
>
> struct QEMUClock {
> - QEMUTimer *active_timers;
> + QEMUTimerList *main_loop_timerlist;
> + QLIST_HEAD(, QEMUTimerList) timerlists;
>
> NotifierList reset_notifiers;
> int64_t last;
>
> - int type;
> + QEMUClockType type;
> bool enabled;
> };
>
> +QEMUClock *qemu_clocks[QEMU_CLOCK_MAX];
> +
> +/* A QEMUTimerList is a list of timers attached to a clock. More
> + * than one QEMUTimerList can be attached to each clock, for instance
> + * used by different AioContexts / threads. Each clock also has
> + * a list of the QEMUTimerLists associated with it, in order that
> + * reenabling the clock can call all the notifiers.
> + */
> +
> +struct QEMUTimerList {
> + QEMUClock *clock;
> + QEMUTimer *active_timers;
> + QLIST_ENTRY(QEMUTimerList) list;
> +};
> +
> struct QEMUTimer {
> int64_t expire_time; /* in nanoseconds */
> - QEMUClock *clock;
> + QEMUTimerList *timer_list;
> QEMUTimerCB *cb;
> void *opaque;
> QEMUTimer *next;
> @@ -93,21 +109,25 @@ static int64_t qemu_next_alarm_deadline(void)
> {
> int64_t delta = INT64_MAX;
> int64_t rtdelta;
> + int64_t hdelta;
>
> - if (!use_icount && vm_clock->enabled && vm_clock->active_timers) {
> - delta = vm_clock->active_timers->expire_time -
> - qemu_get_clock_ns(vm_clock);
> + if (!use_icount && vm_clock->enabled &&
> + vm_clock->main_loop_timerlist->active_timers) {
> + delta = vm_clock->main_loop_timerlist->active_timers->expire_time -
> + qemu_get_clock_ns(vm_clock);
> }
> - if (host_clock->enabled && host_clock->active_timers) {
> - int64_t hdelta = host_clock->active_timers->expire_time -
> - qemu_get_clock_ns(host_clock);
> + if (host_clock->enabled &&
> + host_clock->main_loop_timerlist->active_timers) {
> + hdelta = host_clock->main_loop_timerlist->active_timers->expire_time
> -
> + qemu_get_clock_ns(host_clock);
> if (hdelta < delta) {
> delta = hdelta;
> }
> }
> - if (rt_clock->enabled && rt_clock->active_timers) {
> - rtdelta = (rt_clock->active_timers->expire_time -
> - qemu_get_clock_ns(rt_clock));
> + if (rt_clock->enabled &&
> + rt_clock->main_loop_timerlist->active_timers) {
> + rtdelta = (rt_clock->main_loop_timerlist->active_timers->expire_time
> -
> + qemu_get_clock_ns(rt_clock));
> if (rtdelta < delta) {
> delta = rtdelta;
> }
> @@ -231,11 +251,42 @@ next:
> }
> }
>
> -QEMUClock *rt_clock;
> -QEMUClock *vm_clock;
> -QEMUClock *host_clock;
> +static QEMUTimerList *timerlist_new_from_clock(QEMUClock *clock)
> +{
> + QEMUTimerList *timer_list;
> +
> + /* Assert if we do not have a clock. If you see this
> + * assertion in means that the clocks have not been
> + * initialised before a timerlist is needed. This
> + * normally happens if an AioContext is used before
> + * init_clocks() is called within main().
> + */
> + assert(clock);
> +
> + timer_list = g_malloc0(sizeof(QEMUTimerList));
> + timer_list->clock = clock;
> + QLIST_INSERT_HEAD(&clock->timerlists, timer_list, list);
> + return timer_list;
> +}
> +
> +QEMUTimerList *timerlist_new(QEMUClockType type)
> +{
> + return timerlist_new_from_clock(qemu_clock_ptr(type));
> +}
> +
> +void timerlist_free(QEMUTimerList *timer_list)
> +{
> + assert(!timerlist_has_timers(timer_list));
> + if (timer_list->clock) {
> + QLIST_REMOVE(timer_list, list);
> + if (timer_list->clock->main_loop_timerlist == timer_list) {
> + timer_list->clock->main_loop_timerlist = NULL;
> + }
> + }
> + g_free(timer_list);
> +}
>
> -static QEMUClock *qemu_clock_new(int type)
> +static QEMUClock *qemu_clock_new(QEMUClockType type)
> {
> QEMUClock *clock;
>
> @@ -244,9 +295,15 @@ static QEMUClock *qemu_clock_new(int type)
> clock->enabled = true;
> clock->last = INT64_MIN;
> notifier_list_init(&clock->reset_notifiers);
> + clock->main_loop_timerlist = timerlist_new_from_clock(clock);
> return clock;
> }
>
> +bool qemu_clock_use_for_deadline(QEMUClock *clock)
> +{
> + return !(use_icount && (clock->type == QEMU_CLOCK_VIRTUAL));
> +}
> +
> void qemu_clock_enable(QEMUClock *clock, bool enabled)
> {
> bool old = clock->enabled;
> @@ -256,24 +313,36 @@ void qemu_clock_enable(QEMUClock *clock, bool enabled)
> }
> }
>
> -int64_t qemu_clock_has_timers(QEMUClock *clock)
> +bool timerlist_has_timers(QEMUTimerList *timer_list)
> {
> - return !!clock->active_timers;
> + return !!timer_list->active_timers;
> }
>
> -int64_t qemu_clock_expired(QEMUClock *clock)
> +bool qemu_clock_has_timers(QEMUClock *clock)
> {
> - return (clock->active_timers &&
> - clock->active_timers->expire_time < qemu_get_clock_ns(clock));
> + return timerlist_has_timers(clock->main_loop_timerlist);
> }
>
> -int64_t qemu_clock_deadline(QEMUClock *clock)
> +bool timerlist_expired(QEMUTimerList *timer_list)
> +{
> + return (timer_list->active_timers &&
> + timer_list->active_timers->expire_time <
> + qemu_get_clock_ns(timer_list->clock));
> +}
> +
> +bool qemu_clock_expired(QEMUClock *clock)
> +{
> + return timerlist_expired(clock->main_loop_timerlist);
> +}
> +
> +int64_t timerlist_deadline(QEMUTimerList *timer_list)
> {
> /* To avoid problems with overflow limit this to 2^32. */
> int64_t delta = INT32_MAX;
>
> - if (clock->enabled && clock->active_timers) {
> - delta = clock->active_timers->expire_time - qemu_get_clock_ns(clock);
> + if (timer_list->clock->enabled && timer_list->active_timers) {
> + delta = timer_list->active_timers->expire_time -
> + qemu_get_clock_ns(timer_list->clock);
> }
> if (delta < 0) {
> delta = 0;
> @@ -281,20 +350,26 @@ int64_t qemu_clock_deadline(QEMUClock *clock)
> return delta;
> }
>
> +int64_t qemu_clock_deadline(QEMUClock *clock)
> +{
> + return timerlist_deadline(clock->main_loop_timerlist);
> +}
> +
> /*
> * As above, but return -1 for no deadline, and do not cap to 2^32
> * as we know the result is always positive.
> */
>
> -int64_t qemu_clock_deadline_ns(QEMUClock *clock)
> +int64_t timerlist_deadline_ns(QEMUTimerList *timer_list)
> {
> int64_t delta;
>
> - if (!clock->enabled || !clock->active_timers) {
> + if (!timer_list->clock->enabled || !timer_list->active_timers) {
> return -1;
> }
>
> - delta = clock->active_timers->expire_time - qemu_get_clock_ns(clock);
> + delta = timer_list->active_timers->expire_time -
> + qemu_get_clock_ns(timer_list->clock);
>
> if (delta <= 0) {
> return 0;
> @@ -303,6 +378,21 @@ int64_t qemu_clock_deadline_ns(QEMUClock *clock)
> return delta;
> }
>
> +int64_t qemu_clock_deadline_ns(QEMUClock *clock)
> +{
> + return timerlist_deadline_ns(clock->main_loop_timerlist);
> +}
> +
> +QEMUClock *timerlist_get_clock(QEMUTimerList *timer_list)
> +{
> + return timer_list->clock;
> +}
> +
> +QEMUTimerList *qemu_clock_get_main_loop_timerlist(QEMUClock *clock)
> +{
> + return clock->main_loop_timerlist;
> +}
> +
> /* Transition function to convert a nanosecond timeout to ms
> * This is used where a system does not support ppoll
> */
> @@ -351,19 +441,26 @@ int qemu_poll_ns(GPollFD *fds, uint nfds, int64_t
> timeout)
> }
>
>
> -QEMUTimer *qemu_new_timer(QEMUClock *clock, int scale,
> - QEMUTimerCB *cb, void *opaque)
> +QEMUTimer *timer_new(QEMUTimerList *timer_list, int scale,
> + QEMUTimerCB *cb, void *opaque)
> {
> QEMUTimer *ts;
>
> ts = g_malloc0(sizeof(QEMUTimer));
> - ts->clock = clock;
> + ts->timer_list = timer_list;
> ts->cb = cb;
> ts->opaque = opaque;
> ts->scale = scale;
> return ts;
> }
>
> +QEMUTimer *qemu_new_timer(QEMUClock *clock, int scale,
> + QEMUTimerCB *cb, void *opaque)
> +{
> + return timer_new(clock->main_loop_timerlist,
> + scale, cb, opaque);
> +}
> +
> void qemu_free_timer(QEMUTimer *ts)
> {
> g_free(ts);
> @@ -376,7 +473,7 @@ void qemu_del_timer(QEMUTimer *ts)
>
> /* NOTE: this code must be signal safe because
> qemu_timer_expired() can be called from a signal. */
> - pt = &ts->clock->active_timers;
> + pt = &ts->timer_list->active_timers;
> for(;;) {
> t = *pt;
> if (!t)
> @@ -400,7 +497,7 @@ void qemu_mod_timer_ns(QEMUTimer *ts, int64_t expire_time)
> /* add the timer in the sorted list */
> /* NOTE: this code must be signal safe because
> qemu_timer_expired() can be called from a signal. */
> - pt = &ts->clock->active_timers;
> + pt = &ts->timer_list->active_timers;
> for(;;) {
> t = *pt;
> if (!qemu_timer_expired_ns(t, expire_time)) {
> @@ -413,12 +510,12 @@ void qemu_mod_timer_ns(QEMUTimer *ts, int64_t
> expire_time)
> *pt = ts;
>
> /* Rearm if necessary */
> - if (pt == &ts->clock->active_timers) {
> + if (pt == &ts->timer_list->active_timers) {
> if (!alarm_timer->pending) {
> qemu_rearm_alarm_timer(alarm_timer);
> }
> /* Interrupt execution to force deadline recalculation. */
> - qemu_clock_warp(ts->clock);
> + qemu_clock_warp(ts->timer_list->clock);
> if (use_icount) {
> qemu_notify_event();
> }
> @@ -433,7 +530,7 @@ void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time)
> bool qemu_timer_pending(QEMUTimer *ts)
> {
> QEMUTimer *t;
> - for (t = ts->clock->active_timers; t != NULL; t = t->next) {
> + for (t = ts->timer_list->active_timers; t != NULL; t = t->next) {
> if (t == ts) {
> return true;
> }
> @@ -446,23 +543,24 @@ bool qemu_timer_expired(QEMUTimer *timer_head, int64_t
> current_time)
> return qemu_timer_expired_ns(timer_head, current_time *
> timer_head->scale);
> }
>
> -bool qemu_run_timers(QEMUClock *clock)
> +bool timerlist_run_timers(QEMUTimerList *timer_list)
> {
> QEMUTimer *ts;
> int64_t current_time;
> bool progress = false;
>
> - if (!clock->enabled)
> + if (!timer_list->clock->enabled) {
> return progress;
> + }
>
> - current_time = qemu_get_clock_ns(clock);
> + current_time = qemu_get_clock_ns(timer_list->clock);
> for(;;) {
> - ts = clock->active_timers;
> + ts = timer_list->active_timers;
> if (!qemu_timer_expired_ns(ts, current_time)) {
> break;
> }
> /* remove timer from the list before calling the callback */
> - clock->active_timers = ts->next;
> + timer_list->active_timers = ts->next;
> ts->next = NULL;
>
> /* run the callback (the timer list can be modified) */
> @@ -472,6 +570,11 @@ bool qemu_run_timers(QEMUClock *clock)
> return progress;
> }
>
> +bool qemu_run_timers(QEMUClock *clock)
> +{
> + return timerlist_run_timers(clock->main_loop_timerlist);
> +}
> +
> int64_t qemu_get_clock_ns(QEMUClock *clock)
> {
> int64_t now, last;
> @@ -509,11 +612,13 @@ void qemu_unregister_clock_reset_notifier(QEMUClock
> *clock, Notifier *notifier)
>
> void init_clocks(void)
> {
> - if (!rt_clock) {
> - rt_clock = qemu_clock_new(QEMU_CLOCK_REALTIME);
> - vm_clock = qemu_clock_new(QEMU_CLOCK_VIRTUAL);
> - host_clock = qemu_clock_new(QEMU_CLOCK_HOST);
> + QEMUClockType type;
> + for (type = 0; type < QEMU_CLOCK_MAX; type++) {
> + if (!qemu_clocks[type]) {
> + qemu_clocks[type] = qemu_clock_new(type);
> + }
> }
> +
> #ifdef CONFIG_PRCTL_PR_SET_TIMERSLACK
> prctl(PR_SET_TIMERSLACK, 1, 0, 0, 0);
> #endif
> @@ -530,9 +635,10 @@ bool qemu_run_all_timers(void)
> alarm_timer->pending = false;
>
> /* vm time timers */
> - progress |= qemu_run_timers(vm_clock);
> - progress |= qemu_run_timers(rt_clock);
> - progress |= qemu_run_timers(host_clock);
> + QEMUClockType type;
> + for (type = 0; type < QEMU_CLOCK_MAX; type++) {
> + progress |= qemu_run_timers(qemu_clock_ptr(type));
> + }
>
> /* rearm timer, if not periodic */
> if (alarm_timer->expired) {
>
- Re: [Qemu-devel] [RFC] [PATCHv8 11/30] aio / timers: Add a notify callback to QEMUTimerList, (continued)
- [Qemu-devel] [RFC] [PATCHv8 12/30] aio / timers: aio_ctx_prepare sets timeout from AioContext timers, Alex Bligh, 2013/08/08
- [Qemu-devel] [RFC] [PATCHv8 13/30] aio / timers: Add aio_timer_new wrapper, Alex Bligh, 2013/08/08
- [Qemu-devel] [RFC] [PATCHv8 08/30] aio / timers: Untangle include files, Alex Bligh, 2013/08/08
- [Qemu-devel] [RFC] [PATCHv8 14/30] aio / timers: Convert aio_poll to use AioContext timers' deadline, Alex Bligh, 2013/08/08
- [Qemu-devel] [RFC] [PATCHv8 07/30] aio / timers: Split QEMUClock into QEMUClock and QEMUTimerList, Alex Bligh, 2013/08/08
- Re: [Qemu-devel] [RFC] [PATCHv8 07/30] aio / timers: Split QEMUClock into QEMUClock and QEMUTimerList,
Paolo Bonzini <=
- [Qemu-devel] [RFC] [PATCHv8 15/30] aio / timers: Convert mainloop to use timeout, Alex Bligh, 2013/08/08
- [Qemu-devel] [RFC] [PATCHv8 16/30] aio / timers: On timer modification, qemu_notify or aio_notify, Alex Bligh, 2013/08/08
- [Qemu-devel] [RFC] [PATCHv8 17/30] aio / timers: Introduce new API qemu_timer_new and friends, Alex Bligh, 2013/08/08
- [Qemu-devel] [RFC] [PATCHv8 18/30] aio / timers: Use all timerlists in icount warp calculations, Alex Bligh, 2013/08/08
- [Qemu-devel] [RFC] [PATCHv8 20/30] aio / timers: Remove alarm timers, Alex Bligh, 2013/08/08
- [Qemu-devel] [RFC] [PATCHv8 19/30] aio / timers: Add documentation and new format calls, Alex Bligh, 2013/08/08