aio / timers: Use all timerlists in icount warp calculations
Notify all timerlists derived from vm_clock in icount warp calculations. When calculating timer delay based on vm_clock deadline, use all timerlists. For compatibility, maintain an apparent bug where when using icount, if no vm_clock timer was set, qemu_clock_deadline would return INT32_MAX and always set an icount clock expiry about 2 seconds ahead. NB: thread safety - when different timerlists sit on different threads, this will need some locking. Signed-off-by: Alex Bligh <alex@alex.org.uk> Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
parent
a3a726ae09
commit
ac70aafc28
46
cpus.c
46
cpus.c
@ -267,7 +267,7 @@ static void icount_warp_rt(void *opaque)
|
|||||||
qemu_icount_bias += MIN(warp_delta, delta);
|
qemu_icount_bias += MIN(warp_delta, delta);
|
||||||
}
|
}
|
||||||
if (qemu_clock_expired(vm_clock)) {
|
if (qemu_clock_expired(vm_clock)) {
|
||||||
qemu_notify_event();
|
qemu_clock_notify(vm_clock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
vm_clock_warp_start = -1;
|
vm_clock_warp_start = -1;
|
||||||
@ -278,13 +278,13 @@ void qtest_clock_warp(int64_t dest)
|
|||||||
int64_t clock = qemu_get_clock_ns(vm_clock);
|
int64_t clock = qemu_get_clock_ns(vm_clock);
|
||||||
assert(qtest_enabled());
|
assert(qtest_enabled());
|
||||||
while (clock < dest) {
|
while (clock < dest) {
|
||||||
int64_t deadline = qemu_clock_deadline(vm_clock);
|
int64_t deadline = qemu_clock_deadline_ns_all(vm_clock);
|
||||||
int64_t warp = MIN(dest - clock, deadline);
|
int64_t warp = MIN(dest - clock, deadline);
|
||||||
qemu_icount_bias += warp;
|
qemu_icount_bias += warp;
|
||||||
qemu_run_timers(vm_clock);
|
qemu_run_timers(vm_clock);
|
||||||
clock = qemu_get_clock_ns(vm_clock);
|
clock = qemu_get_clock_ns(vm_clock);
|
||||||
}
|
}
|
||||||
qemu_notify_event();
|
qemu_clock_notify(vm_clock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void qemu_clock_warp(QEMUClock *clock)
|
void qemu_clock_warp(QEMUClock *clock)
|
||||||
@ -319,7 +319,18 @@ void qemu_clock_warp(QEMUClock *clock)
|
|||||||
}
|
}
|
||||||
|
|
||||||
vm_clock_warp_start = qemu_get_clock_ns(rt_clock);
|
vm_clock_warp_start = qemu_get_clock_ns(rt_clock);
|
||||||
deadline = qemu_clock_deadline(vm_clock);
|
/* We want to use the earliest deadline from ALL vm_clocks */
|
||||||
|
deadline = qemu_clock_deadline_ns_all(vm_clock);
|
||||||
|
|
||||||
|
/* Maintain prior (possibly buggy) behaviour where if no deadline
|
||||||
|
* was set (as there is no vm_clock timer) or it is more than
|
||||||
|
* INT32_MAX nanoseconds ahead, we still use INT32_MAX
|
||||||
|
* nanoseconds.
|
||||||
|
*/
|
||||||
|
if ((deadline < 0) || (deadline > INT32_MAX)) {
|
||||||
|
deadline = INT32_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
if (deadline > 0) {
|
if (deadline > 0) {
|
||||||
/*
|
/*
|
||||||
* Ensure the vm_clock proceeds even when the virtual CPU goes to
|
* Ensure the vm_clock proceeds even when the virtual CPU goes to
|
||||||
@ -338,8 +349,8 @@ void qemu_clock_warp(QEMUClock *clock)
|
|||||||
* packets continuously instead of every 100ms.
|
* packets continuously instead of every 100ms.
|
||||||
*/
|
*/
|
||||||
qemu_mod_timer(icount_warp_timer, vm_clock_warp_start + deadline);
|
qemu_mod_timer(icount_warp_timer, vm_clock_warp_start + deadline);
|
||||||
} else {
|
} else if (deadline == 0) {
|
||||||
qemu_notify_event();
|
qemu_clock_notify(vm_clock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -866,8 +877,13 @@ static void *qemu_tcg_cpu_thread_fn(void *arg)
|
|||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
tcg_exec_all();
|
tcg_exec_all();
|
||||||
if (use_icount && qemu_clock_deadline(vm_clock) <= 0) {
|
|
||||||
qemu_notify_event();
|
if (use_icount) {
|
||||||
|
int64_t deadline = qemu_clock_deadline_ns_all(vm_clock);
|
||||||
|
|
||||||
|
if (deadline == 0) {
|
||||||
|
qemu_clock_notify(vm_clock);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
qemu_tcg_wait_io_event();
|
qemu_tcg_wait_io_event();
|
||||||
}
|
}
|
||||||
@ -1145,11 +1161,23 @@ static int tcg_cpu_exec(CPUArchState *env)
|
|||||||
#endif
|
#endif
|
||||||
if (use_icount) {
|
if (use_icount) {
|
||||||
int64_t count;
|
int64_t count;
|
||||||
|
int64_t deadline;
|
||||||
int decr;
|
int decr;
|
||||||
qemu_icount -= (env->icount_decr.u16.low + env->icount_extra);
|
qemu_icount -= (env->icount_decr.u16.low + env->icount_extra);
|
||||||
env->icount_decr.u16.low = 0;
|
env->icount_decr.u16.low = 0;
|
||||||
env->icount_extra = 0;
|
env->icount_extra = 0;
|
||||||
count = qemu_icount_round(qemu_clock_deadline(vm_clock));
|
deadline = qemu_clock_deadline_ns_all(vm_clock);
|
||||||
|
|
||||||
|
/* Maintain prior (possibly buggy) behaviour where if no deadline
|
||||||
|
* was set (as there is no vm_clock timer) or it is more than
|
||||||
|
* INT32_MAX nanoseconds ahead, we still use INT32_MAX
|
||||||
|
* nanoseconds.
|
||||||
|
*/
|
||||||
|
if ((deadline < 0) || (deadline > INT32_MAX)) {
|
||||||
|
deadline = INT32_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
count = qemu_icount_round(deadline);
|
||||||
qemu_icount += count;
|
qemu_icount += count;
|
||||||
decr = (count > 0xffff) ? 0xffff : count;
|
decr = (count > 0xffff) ? 0xffff : count;
|
||||||
count -= decr;
|
count -= decr;
|
||||||
|
@ -103,6 +103,7 @@ int64_t qemu_clock_deadline(QEMUClock *clock);
|
|||||||
* @clock: the clock to operate on
|
* @clock: the clock to operate on
|
||||||
*
|
*
|
||||||
* Calculate the timeout of the earliest expiring timer
|
* Calculate the timeout of the earliest expiring timer
|
||||||
|
* on the default timer list associated with the clock
|
||||||
* in nanoseconds, or -1 if no timer is set to expire.
|
* in nanoseconds, or -1 if no timer is set to expire.
|
||||||
*
|
*
|
||||||
* Returns: time until expiry in nanoseconds or -1
|
* Returns: time until expiry in nanoseconds or -1
|
||||||
@ -125,6 +126,18 @@ int64_t qemu_clock_deadline_ns(QEMUClock *clock);
|
|||||||
*/
|
*/
|
||||||
bool qemu_clock_use_for_deadline(QEMUClock *clock);
|
bool qemu_clock_use_for_deadline(QEMUClock *clock);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* qemu_clock_use_for_deadline:
|
||||||
|
* @clock: the clock to operate on
|
||||||
|
*
|
||||||
|
* Calculate the deadline across all timer lists associated
|
||||||
|
* with a clock (as opposed to just the default one)
|
||||||
|
* in nanoseconds, or -1 if no timer is set to expire.
|
||||||
|
*
|
||||||
|
* Returns: time until expiry in nanoseconds or -1
|
||||||
|
*/
|
||||||
|
int64_t qemu_clock_deadline_ns_all(QEMUClock *clock);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* qemu_clock_get_main_loop_timerlist:
|
* qemu_clock_get_main_loop_timerlist:
|
||||||
* @clock: the clock to operate on
|
* @clock: the clock to operate on
|
||||||
|
16
qemu-timer.c
16
qemu-timer.c
@ -392,6 +392,22 @@ int64_t qemu_clock_deadline_ns(QEMUClock *clock)
|
|||||||
return timerlist_deadline_ns(clock->main_loop_timerlist);
|
return timerlist_deadline_ns(clock->main_loop_timerlist);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Calculate the soonest deadline across all timerlists attached
|
||||||
|
* to the clock. This is used for the icount timeout so we
|
||||||
|
* ignore whether or not the clock should be used in deadline
|
||||||
|
* calculations.
|
||||||
|
*/
|
||||||
|
int64_t qemu_clock_deadline_ns_all(QEMUClock *clock)
|
||||||
|
{
|
||||||
|
int64_t deadline = -1;
|
||||||
|
QEMUTimerList *timer_list;
|
||||||
|
QLIST_FOREACH(timer_list, &clock->timerlists, list) {
|
||||||
|
deadline = qemu_soonest_timeout(deadline,
|
||||||
|
timerlist_deadline_ns(timer_list));
|
||||||
|
}
|
||||||
|
return deadline;
|
||||||
|
}
|
||||||
|
|
||||||
QEMUClock *timerlist_get_clock(QEMUTimerList *timer_list)
|
QEMUClock *timerlist_get_clock(QEMUTimerList *timer_list)
|
||||||
{
|
{
|
||||||
return timer_list->clock;
|
return timer_list->clock;
|
||||||
|
2
qtest.c
2
qtest.c
@ -412,7 +412,7 @@ static void qtest_process_command(CharDriverState *chr, gchar **words)
|
|||||||
if (words[1]) {
|
if (words[1]) {
|
||||||
ns = strtoll(words[1], NULL, 0);
|
ns = strtoll(words[1], NULL, 0);
|
||||||
} else {
|
} else {
|
||||||
ns = qemu_clock_deadline(vm_clock);
|
ns = qemu_clock_deadline_ns_all(vm_clock);
|
||||||
}
|
}
|
||||||
qtest_clock_warp(qemu_get_clock_ns(vm_clock) + ns);
|
qtest_clock_warp(qemu_get_clock_ns(vm_clock) + ns);
|
||||||
qtest_send_prefix(chr);
|
qtest_send_prefix(chr);
|
||||||
|
Loading…
Reference in New Issue
Block a user