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 <a...@alex.org.uk> > --- > 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) { >