qemu-timer: check active_timers outside lock/event

This avoids taking the active_timers_lock or resetting/setting the
timers_done_ev if there are no active timers.  This removes a small
(2-3%) source of overhead for dataplane.  The list is then checked
again inside the lock, or a NULL pointer could be dereferenced.

Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
Paolo Bonzini 2016-12-01 09:58:02 +01:00
parent e7a9f35321
commit 8caa05d889
1 changed files with 16 additions and 4 deletions

View File

@ -174,7 +174,7 @@ void qemu_clock_enable(QEMUClockType type, bool enabled)
bool timerlist_has_timers(QEMUTimerList *timer_list) bool timerlist_has_timers(QEMUTimerList *timer_list)
{ {
return !!timer_list->active_timers; return !!atomic_read(&timer_list->active_timers);
} }
bool qemu_clock_has_timers(QEMUClockType type) bool qemu_clock_has_timers(QEMUClockType type)
@ -187,6 +187,10 @@ bool timerlist_expired(QEMUTimerList *timer_list)
{ {
int64_t expire_time; int64_t expire_time;
if (!atomic_read(&timer_list->active_timers)) {
return false;
}
qemu_mutex_lock(&timer_list->active_timers_lock); qemu_mutex_lock(&timer_list->active_timers_lock);
if (!timer_list->active_timers) { if (!timer_list->active_timers) {
qemu_mutex_unlock(&timer_list->active_timers_lock); qemu_mutex_unlock(&timer_list->active_timers_lock);
@ -214,6 +218,10 @@ int64_t timerlist_deadline_ns(QEMUTimerList *timer_list)
int64_t delta; int64_t delta;
int64_t expire_time; int64_t expire_time;
if (!atomic_read(&timer_list->active_timers)) {
return -1;
}
if (!timer_list->clock->enabled) { if (!timer_list->clock->enabled) {
return -1; return -1;
} }
@ -363,7 +371,7 @@ static void timer_del_locked(QEMUTimerList *timer_list, QEMUTimer *ts)
if (!t) if (!t)
break; break;
if (t == ts) { if (t == ts) {
*pt = t->next; atomic_set(pt, t->next);
break; break;
} }
pt = &t->next; pt = &t->next;
@ -386,7 +394,7 @@ static bool timer_mod_ns_locked(QEMUTimerList *timer_list,
} }
ts->expire_time = MAX(expire_time, 0); ts->expire_time = MAX(expire_time, 0);
ts->next = *pt; ts->next = *pt;
*pt = ts; atomic_set(pt, ts);
return pt == &timer_list->active_timers; return pt == &timer_list->active_timers;
} }
@ -481,8 +489,12 @@ bool timerlist_run_timers(QEMUTimerList *timer_list)
QEMUTimerCB *cb; QEMUTimerCB *cb;
void *opaque; void *opaque;
if (!atomic_read(&timer_list->active_timers)) {
return false;
}
qemu_event_reset(&timer_list->timers_done_ev); qemu_event_reset(&timer_list->timers_done_ev);
if (!timer_list->clock->enabled || !timer_list->active_timers) { if (!timer_list->clock->enabled) {
goto out; goto out;
} }