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:
parent
2028834574
commit
8156be5610
20
cpus.c
20
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) {
|
||||
|
2
cpus.h
2
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;
|
||||
|
@ -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;
|
||||
|
@ -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
45
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);
|
||||
|
Loading…
Reference in New Issue
Block a user