From 8156be561019bd0fc17729e9a528f6c81eea9186 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 28 Mar 2012 15:42:04 +0200 Subject: [PATCH] qtest: add clock management This patch combines qtest and -icount together to turn the vm_clock into a source that can be fully managed by the client. To this end new commands clock_step and clock_set are added. Hooking them with libqtest is left as an exercise to the reader. Signed-off-by: Paolo Bonzini Signed-off-by: Anthony Liguori --- cpus.c | 20 ++++++++++++++++++++ cpus.h | 2 ++ qemu-timer.c | 2 +- qemu-timer.h | 1 + qtest.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 69 insertions(+), 1 deletion(-) diff --git a/cpus.c b/cpus.c index ab8d67b9d8..eb22bd5df1 100644 --- a/cpus.c +++ b/cpus.c @@ -34,6 +34,7 @@ #include "qemu-thread.h" #include "cpus.h" +#include "qtest.h" #include "main-loop.h" #ifndef _WIN32 @@ -238,6 +239,20 @@ static void icount_warp_rt(void *opaque) vm_clock_warp_start = -1; } +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 warp = MIN(dest - clock, deadline); + qemu_icount_bias += warp; + qemu_run_timers(vm_clock); + clock = qemu_get_clock_ns(vm_clock); + } + qemu_notify_event(); +} + void qemu_clock_warp(QEMUClock *clock) { int64_t deadline; @@ -264,6 +279,11 @@ void qemu_clock_warp(QEMUClock *clock) return; } + if (qtest_enabled()) { + /* When testing, qtest commands advance icount. */ + return; + } + vm_clock_warp_start = qemu_get_clock_ns(rt_clock); deadline = qemu_clock_deadline(vm_clock); if (deadline > 0) { diff --git a/cpus.h b/cpus.h index 4ea2fe2c22..81bd81773f 100644 --- a/cpus.h +++ b/cpus.h @@ -11,6 +11,8 @@ void cpu_synchronize_all_states(void); void cpu_synchronize_all_post_reset(void); void cpu_synchronize_all_post_init(void); +void qtest_clock_warp(int64_t dest); + /* vl.c */ extern int smp_cores; extern int smp_threads; diff --git a/qemu-timer.c b/qemu-timer.c index d7f56e55f9..80bcc563e0 100644 --- a/qemu-timer.c +++ b/qemu-timer.c @@ -397,7 +397,7 @@ int qemu_timer_expired(QEMUTimer *timer_head, int64_t current_time) return qemu_timer_expired_ns(timer_head, current_time * timer_head->scale); } -static void qemu_run_timers(QEMUClock *clock) +void qemu_run_timers(QEMUClock *clock) { QEMUTimer **ptimer_head, *ts; int64_t current_time; diff --git a/qemu-timer.h b/qemu-timer.h index de17f3b1a1..661bbe76b2 100644 --- a/qemu-timer.h +++ b/qemu-timer.h @@ -59,6 +59,7 @@ int qemu_timer_pending(QEMUTimer *ts); int qemu_timer_expired(QEMUTimer *timer_head, int64_t current_time); uint64_t qemu_timer_expire_time_ns(QEMUTimer *ts); +void qemu_run_timers(QEMUClock *clock); void qemu_run_all_timers(void); int qemu_alarm_pending(void); void configure_alarms(char const *opt); diff --git a/qtest.c b/qtest.c index a1eca49888..53e2b7942c 100644 --- a/qtest.c +++ b/qtest.c @@ -18,6 +18,7 @@ #include "memory.h" #include "hw/irq.h" #include "sysemu.h" +#include "cpus.h" #define MAX_IRQ 256 @@ -44,6 +45,30 @@ static bool qtest_opened; * * Valid requests * + * Clock management: + * + * The qtest client is completely in charge of the vm_clock. qtest commands + * let you adjust the value of the clock (monotonically). All the commands + * return the current value of the clock in nanoseconds. + * + * > clock_step + * < OK VALUE + * + * Advance the clock to the next deadline. Useful when waiting for + * asynchronous events. + * + * > clock_step NS + * < OK VALUE + * + * Advance the clock by NS nanoseconds. + * + * > clock_set NS + * < OK VALUE + * + * Advance the clock to NS nanoseconds (do nothing if it's already past). + * + * PIO and memory access: + * * > outb ADDR VALUE * < OK * @@ -299,6 +324,25 @@ static void qtest_process_command(CharDriverState *chr, gchar **words) qtest_send_prefix(chr); qtest_send(chr, "OK\n"); + } else if (strcmp(words[0], "clock_step") == 0) { + int64_t ns; + + if (words[1]) { + ns = strtoll(words[1], NULL, 0); + } else { + ns = qemu_clock_deadline(vm_clock); + } + qtest_clock_warp(qemu_get_clock_ns(vm_clock) + ns); + qtest_send_prefix(chr); + qtest_send(chr, "OK %"PRIi64"\n", (int64_t)qemu_get_clock_ns(vm_clock)); + } else if (strcmp(words[0], "clock_set") == 0) { + int64_t ns; + + g_assert(words[1]); + ns = strtoll(words[1], NULL, 0); + qtest_clock_warp(ns); + qtest_send_prefix(chr); + qtest_send(chr, "OK %"PRIi64"\n", (int64_t)qemu_get_clock_ns(vm_clock)); } else { qtest_send_prefix(chr); qtest_send(chr, "FAIL Unknown command `%s'\n", words[0]); @@ -377,6 +421,7 @@ int qtest_init(void) g_assert(qtest_chrdev != NULL); + configure_icount("0"); chr = qemu_chr_new("qtest", qtest_chrdev, NULL); qemu_chr_add_handlers(chr, qtest_can_read, qtest_read, qtest_event, chr);