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 <pbonzini@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
This commit is contained in:
Paolo Bonzini 2012-03-28 15:42:04 +02:00 committed by Anthony Liguori
parent 2028834574
commit 8156be5610
5 changed files with 69 additions and 1 deletions

20
cpus.c
View File

@ -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) {

2
cpus.h
View File

@ -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;

View File

@ -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;

View File

@ -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);

45
qtest.c
View File

@ -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);