qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [RFC] [PATCHv7 07/22] aio / timers: Split QEMUClock int


From: liu ping fan
Subject: Re: [Qemu-devel] [RFC] [PATCHv7 07/22] aio / timers: Split QEMUClock into QEMUClock and QEMUTimerList
Date: Thu, 8 Aug 2013 14:12:58 +0800

On Wed, Aug 7, 2013 at 7:49 AM, Alex Bligh <address@hidden> wrote:
> Split QEMUClock into QEMUClock and QEMUTimerList so that we can
> have more than one QEMUTimerList associated with the same clock.
>
> Introduce a default_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

I think that as clock event source, QemuClock can not be created
arbitrary, i.e only three instance allowed. So what about comment
"Fold *_clock into qemu_clocks[]"

> 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 |  408 
> +++++++++++++++++++++++++++++++++++++++++++++++---
>  qemu-timer.c         |  201 +++++++++++++++++++------
>  2 files changed, 538 insertions(+), 71 deletions(-)
>
> diff --git a/include/qemu/timer.h b/include/qemu/timer.h
> index 0d368cc..eb2b99e 100644
> --- a/include/qemu/timer.h
> +++ b/include/qemu/timer.h
> @@ -11,30 +11,71 @@
>  #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_get_clock:
> + * @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_get_clock(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_get_clock(QEMU_CLOCK_REALTIME))
> +#define vm_clock (qemu_get_clock(QEMU_CLOCK_VIRTUAL))
> +#define host_clock (qemu_get_clock(QEMU_CLOCK_HOST))
>
>  /**
>   * qemu_clock_new:
> @@ -44,7 +85,7 @@ extern QEMUClock *host_clock;
>   *
>   * Returns: A pointer to the clock object
>   */
> -QEMUClock *qemu_clock_new(int type);
> +QEMUClock *qemu_clock_new(QEMUClockType type);
>
>  /**
>   * qemu_clock_free:
> @@ -55,8 +96,8 @@ QEMUClock *qemu_clock_new(int type);
>  void qemu_clock_free(QEMUClock *clock);
>
>  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);
>
>  /**
> @@ -71,6 +112,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_default_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_default_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
>   *
> @@ -102,6 +261,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);
> @@ -110,11 +284,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);
> +}
> +
> +/**
> + * 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.
>   */
> @@ -123,7 +387,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.
>   */
> @@ -156,18 +421,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 388b98c..46f4029 100644
> --- a/qemu-timer.c
> +++ b/qemu-timer.c
> @@ -49,18 +49,34 @@
>  /* timers */
>
>  struct QEMUClock {
> -    QEMUTimer *active_timers;
> +    QEMUTimerList *default_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->default_timerlist->active_timers) {
> +        delta = vm_clock->default_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->default_timerlist->active_timers) {
> +        hdelta = host_clock->default_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->default_timerlist->active_timers) {
> +        rtdelta = (rt_clock->default_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_get_clock(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->default_timerlist == timer_list) {
> +            timer_list->clock->default_timerlist = NULL;
> +        }
> +    }
> +    g_free(timer_list);
> +}
>
> -QEMUClock *qemu_clock_new(int type)
> +QEMUClock *qemu_clock_new(QEMUClockType type)
>  {
>      QEMUClock *clock;
>
> @@ -244,14 +295,21 @@ QEMUClock *qemu_clock_new(int type)
>      clock->enabled = true;
>      clock->last = INT64_MIN;
>      notifier_list_init(&clock->reset_notifiers);
> +    clock->default_timerlist = timerlist_new_from_clock(clock);
>      return clock;
>  }
>
>  void qemu_clock_free(QEMUClock *clock)
>  {
> +    timerlist_free(clock->default_timerlist);
>      g_free(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;
> @@ -261,24 +319,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->default_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->default_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;
> @@ -286,20 +356,26 @@ int64_t qemu_clock_deadline(QEMUClock *clock)
>      return delta;
>  }
>
> +int64_t qemu_clock_deadline(QEMUClock *clock)
> +{
> +    return timerlist_deadline(clock->default_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;
> @@ -308,6 +384,21 @@ int64_t qemu_clock_deadline_ns(QEMUClock *clock)
>      return delta;
>  }
>
> +int64_t qemu_clock_deadline_ns(QEMUClock *clock)
> +{
> +    return timerlist_deadline_ns(clock->default_timerlist);
> +}
> +
> +QEMUClock *timerlist_get_clock(QEMUTimerList *timer_list)
> +{
> +    return timer_list->clock;
> +}
> +
> +QEMUTimerList *qemu_clock_get_default_timerlist(QEMUClock *clock)
> +{
> +    return clock->default_timerlist;
> +}
> +
>  /* Transition function to convert a nanosecond timeout to ms
>   * This is used where a system does not support ppoll
>   */
> @@ -356,19 +447,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->default_timerlist,
> +                     scale, cb, opaque);
> +}
> +
>  void qemu_free_timer(QEMUTimer *ts)
>  {
>      g_free(ts);
> @@ -381,7 +479,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)
> @@ -405,7 +503,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)) {
> @@ -418,12 +516,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();
>          }
> @@ -438,7 +536,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;
>          }
> @@ -451,23 +549,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) */
> @@ -477,6 +576,11 @@ bool qemu_run_timers(QEMUClock *clock)
>      return progress;
>  }
>
> +bool qemu_run_timers(QEMUClock *clock)
> +{
> +    return timerlist_run_timers(clock->default_timerlist);
> +}
> +
>  int64_t qemu_get_clock_ns(QEMUClock *clock)
>  {
>      int64_t now, last;
> @@ -514,11 +618,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
> @@ -535,9 +641,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_get_clock(type));
> +    }
>
>      /* rearm timer, if not periodic */
>      if (alarm_timer->expired) {
> --
> 1.7.9.5
>



reply via email to

[Prev in Thread] Current Thread [Next in Thread]