qemu-devel
[Top][All Lists]
Advanced

[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) {
> 




reply via email to

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