To allow timer to run on the different backend threads, we will arm the thread's AioContext with its own timer list. So separate these kind of info from QemuClock.
Signed-off-by: Liu Ping Fan <pingf...@linux.vnet.ibm.com> --- qemu-timer.c | 106 ++++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 68 insertions(+), 38 deletions(-) diff --git a/qemu-timer.c b/qemu-timer.c index 32c70ed..0ee68dc 100644 --- a/qemu-timer.c +++ b/qemu-timer.c @@ -30,6 +30,7 @@ #include "qemu/timer.h" #include "qemu/thread.h" +#include "qemu/tls.h" #ifdef CONFIG_POSIX #include <pthread.h> #endif @@ -44,11 +45,16 @@ #define QEMU_CLOCK_REALTIME 0 #define QEMU_CLOCK_VIRTUAL 1 #define QEMU_CLOCK_HOST 2 +#define QEMU_CLOCK_MAXCNT 3 -struct QEMUClock { +typedef struct TimerList { QEMUTimer *active_timers; QemuMutex active_timers_lock; +} TimerList; + +static TimerList timer_list[QEMU_CLOCK_MAXCNT]; +struct QEMUClock { NotifierList reset_notifiers; int64_t last; @@ -58,7 +64,7 @@ struct QEMUClock { struct QEMUTimer { int64_t expire_time; /* in nanoseconds */ - QEMUClock *clock; + TimerList *list; QEMUTimerCB *cb; void *opaque; QEMUTimer *next; @@ -122,6 +128,13 @@ void alarm_timer_destroy(struct qemu_alarm_timer *t) g_free(t); } +static TimerList *clock_to_timerlist(QEMUClock *clock) +{ + int type = clock->type; + + return &timer_list[type]; +} + static bool qemu_timer_expired_ns(QEMUTimer *timer_head, int64_t current_time) { return timer_head && (timer_head->expire_time <= current_time); @@ -131,17 +144,19 @@ static int64_t qemu_next_clock_deadline(QEMUClock *clock, int64_t delta) { int64_t expire_time, next; bool has_timer = false; + TimerList *tlist; if (!clock->enabled) { return delta; } - qemu_mutex_lock(&clock->active_timers_lock); - if (clock->active_timers) { + tlist = clock_to_timerlist(clock); + qemu_mutex_lock(&tlist->active_timers_lock); + if (tlist->active_timers) { has_timer = true; - expire_time = clock->active_timers->expire_time; + expire_time = tlist->active_timers->expire_time; } - qemu_mutex_unlock(&clock->active_timers_lock); + qemu_mutex_unlock(&tlist->active_timers_lock); if (!has_timer) { return delta; } @@ -294,16 +309,25 @@ QEMUClock *rt_clock; QEMUClock *vm_clock; QEMUClock *host_clock; +static void timer_list_init(TimerList *tlist) +{ + qemu_mutex_init(&tlist->active_timers_lock); + tlist->active_timers = NULL; +} + static QEMUClock *qemu_new_clock(int type) { QEMUClock *clock; + TimerList *tlist; clock = g_malloc0(sizeof(QEMUClock)); clock->type = type; clock->enabled = true; clock->last = INT64_MIN; notifier_list_init(&clock->reset_notifiers); - qemu_mutex_init(&clock->active_timers_lock); + tlist = clock_to_timerlist(clock); + timer_list_init(tlist); + return clock; } @@ -319,10 +343,11 @@ void qemu_clock_enable(QEMUClock *clock, bool enabled) int64_t qemu_clock_has_timers(QEMUClock *clock) { bool has_timers; + TimerList *tlist = clock_to_timerlist(clock); - qemu_mutex_lock(&clock->active_timers_lock); - has_timers = !!clock->active_timers; - qemu_mutex_unlock(&clock->active_timers_lock); + qemu_mutex_lock(&tlist->active_timers_lock); + has_timers = !!tlist->active_timers; + qemu_mutex_unlock(&tlist->active_timers_lock); return has_timers; } @@ -330,11 +355,12 @@ int64_t qemu_clock_expired(QEMUClock *clock) { bool has_timers; int64_t expire_time; + TimerList *tlist = clock_to_timerlist(clock); - qemu_mutex_lock(&clock->active_timers_lock); - has_timers = clock->active_timers; - expire_time = clock->active_timers->expire_time; - qemu_mutex_unlock(&clock->active_timers_lock); + qemu_mutex_lock(&tlist->active_timers_lock); + has_timers = tlist->active_timers; + expire_time = tlist->active_timers->expire_time; + qemu_mutex_unlock(&tlist->active_timers_lock); return has_timers && expire_time < qemu_get_clock_ns(clock); } @@ -345,11 +371,12 @@ int64_t qemu_clock_deadline(QEMUClock *clock) int64_t delta = INT32_MAX; bool has_timers; int64_t expire_time; + TimerList *tlist = clock_to_timerlist(clock); - qemu_mutex_lock(&clock->active_timers_lock); - has_timers = clock->active_timers; - expire_time = clock->active_timers->expire_time; - qemu_mutex_unlock(&clock->active_timers_lock); + qemu_mutex_lock(&tlist->active_timers_lock); + has_timers = tlist->active_timers; + expire_time = tlist->active_timers->expire_time; + qemu_mutex_unlock(&tlist->active_timers_lock); if (has_timers) { delta = expire_time - qemu_get_clock_ns(clock); @@ -366,7 +393,7 @@ QEMUTimer *qemu_new_timer(QEMUClock *clock, int scale, QEMUTimer *ts; ts = g_malloc0(sizeof(QEMUTimer)); - ts->clock = clock; + ts->list = clock_to_timerlist(clock); ts->cb = cb; ts->opaque = opaque; ts->scale = scale; @@ -381,11 +408,11 @@ void qemu_free_timer(QEMUTimer *ts) /* stop a timer, but do not dealloc it */ void qemu_del_timer(QEMUTimer *ts) { - QEMUClock *clock = ts->clock; + TimerList *tlist = ts->list; QEMUTimer **pt, *t; - qemu_mutex_lock(&clock->active_timers_lock); - pt = &ts->clock->active_timers; + qemu_mutex_lock(&tlist->active_timers_lock); + pt = &tlist->active_timers; for(;;) { t = *pt; if (!t) @@ -396,14 +423,14 @@ void qemu_del_timer(QEMUTimer *ts) } pt = &t->next; } - qemu_mutex_unlock(&clock->active_timers_lock); + qemu_mutex_unlock(&tlist->active_timers_lock); } /* modify the current timer so that it will be fired when current_time >= expire_time. The corresponding callback will be called. */ void qemu_mod_timer_ns(QEMUTimer *ts, int64_t expire_time) { - QEMUClock *clock = ts->clock; + TimerList *tlist = ts->list; QEMUTimer **pt, *t; AioContext *ctx = *tls_get_thread_aio_context(); struct qemu_alarm_timer *alarm_timer = ctx->alarm_timer; @@ -411,8 +438,8 @@ void qemu_mod_timer_ns(QEMUTimer *ts, int64_t expire_time) qemu_del_timer(ts); /* add the timer in the sorted list */ - qemu_mutex_lock(&clock->active_timers_lock); - pt = &clock->active_timers; + qemu_mutex_lock(&tlist->active_timers_lock); + pt = &tlist->active_timers; for(;;) { t = *pt; if (!qemu_timer_expired_ns(t, expire_time)) { @@ -423,10 +450,10 @@ void qemu_mod_timer_ns(QEMUTimer *ts, int64_t expire_time) ts->expire_time = expire_time; ts->next = *pt; *pt = ts; - qemu_mutex_unlock(&clock->active_timers_lock); + qemu_mutex_unlock(&tlist->active_timers_lock); /* Rearm if necessary */ - if (pt == &ts->clock->active_timers) { + if (pt == &tlist->active_timers) { qemu_mutex_lock(&alarm_timer->timer_modified_lock); alarm_timer->timer_modified = true; qemu_mutex_unlock(&alarm_timer->timer_modified_lock); @@ -442,15 +469,15 @@ void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time) bool qemu_timer_pending(QEMUTimer *ts) { QEMUTimer *t; - QEMUClock *clock = ts->clock; + TimerList *tlist = ts->list; - qemu_mutex_lock(&clock->active_timers_lock); - for (t = ts->clock->active_timers; t != NULL; t = t->next) { + qemu_mutex_lock(&tlist->active_timers_lock); + for (t = tlist->active_timers; t != NULL; t = t->next) { if (t == ts) { break; } } - qemu_mutex_unlock(&clock->active_timers_lock); + qemu_mutex_unlock(&tlist->active_timers_lock); return t; } @@ -463,22 +490,25 @@ void qemu_run_timers(QEMUClock *clock) { QEMUTimer *ts; int64_t current_time; - + TimerList *tlist; + if (!clock->enabled) return; current_time = qemu_get_clock_ns(clock); + tlist = clock_to_timerlist(clock); + for(;;) { - qemu_mutex_lock(&clock->active_timers_lock); - ts = clock->active_timers; + qemu_mutex_lock(&tlist->active_timers_lock); + ts = tlist->active_timers; if (!qemu_timer_expired_ns(ts, current_time)) { - qemu_mutex_unlock(&clock->active_timers_lock); + qemu_mutex_unlock(&tlist->active_timers_lock); break; } /* remove timer from the list before calling the callback */ - clock->active_timers = ts->next; + tlist->active_timers = ts->next; ts->next = NULL; - qemu_mutex_unlock(&clock->active_timers_lock); + qemu_mutex_unlock(&tlist->active_timers_lock); /* run the callback (the timer list can be modified) */ ts->cb(ts->opaque); -- 1.8.1.4