diff --git a/cpus.c b/cpus.c index 70cc6171e2..254eb4c3e8 100644 --- a/cpus.c +++ b/cpus.c @@ -267,7 +267,7 @@ static void icount_warp_rt(void *opaque) qemu_icount_bias += MIN(warp_delta, delta); } if (qemu_clock_expired(vm_clock)) { - qemu_notify_event(); + qemu_clock_notify(vm_clock); } } 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); assert(qtest_enabled()); 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); qemu_icount_bias += warp; qemu_run_timers(vm_clock); clock = qemu_get_clock_ns(vm_clock); } - qemu_notify_event(); + qemu_clock_notify(vm_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); - 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) { /* * 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. */ qemu_mod_timer(icount_warp_timer, vm_clock_warp_start + deadline); - } else { - qemu_notify_event(); + } else if (deadline == 0) { + qemu_clock_notify(vm_clock); } } @@ -866,8 +877,13 @@ static void *qemu_tcg_cpu_thread_fn(void *arg) while (1) { 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(); } @@ -1145,11 +1161,23 @@ static int tcg_cpu_exec(CPUArchState *env) #endif if (use_icount) { int64_t count; + int64_t deadline; int decr; qemu_icount -= (env->icount_decr.u16.low + env->icount_extra); env->icount_decr.u16.low = 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; decr = (count > 0xffff) ? 0xffff : count; count -= decr; diff --git a/include/qemu/timer.h b/include/qemu/timer.h index 205324481a..1265ad2991 100644 --- a/include/qemu/timer.h +++ b/include/qemu/timer.h @@ -103,6 +103,7 @@ int64_t qemu_clock_deadline(QEMUClock *clock); * @clock: the clock to operate on * * 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. * * 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); +/** + * 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: * @clock: the clock to operate on diff --git a/qemu-timer.c b/qemu-timer.c index 746ba8b7e1..b56bfde706 100644 --- a/qemu-timer.c +++ b/qemu-timer.c @@ -392,6 +392,22 @@ int64_t qemu_clock_deadline_ns(QEMUClock *clock) 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) { return timer_list->clock; diff --git a/qtest.c b/qtest.c index 74f1842c1e..c038e24d51 100644 --- a/qtest.c +++ b/qtest.c @@ -412,7 +412,7 @@ static void qtest_process_command(CharDriverState *chr, gchar **words) if (words[1]) { ns = strtoll(words[1], NULL, 0); } 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_send_prefix(chr);