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 "qemu-thread.h"
|
||||||
#include "cpus.h"
|
#include "cpus.h"
|
||||||
|
#include "qtest.h"
|
||||||
#include "main-loop.h"
|
#include "main-loop.h"
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
@ -238,6 +239,20 @@ static void icount_warp_rt(void *opaque)
|
|||||||
vm_clock_warp_start = -1;
|
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)
|
void qemu_clock_warp(QEMUClock *clock)
|
||||||
{
|
{
|
||||||
int64_t deadline;
|
int64_t deadline;
|
||||||
@ -264,6 +279,11 @@ void qemu_clock_warp(QEMUClock *clock)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (qtest_enabled()) {
|
||||||
|
/* When testing, qtest commands advance icount. */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
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);
|
deadline = qemu_clock_deadline(vm_clock);
|
||||||
if (deadline > 0) {
|
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_reset(void);
|
||||||
void cpu_synchronize_all_post_init(void);
|
void cpu_synchronize_all_post_init(void);
|
||||||
|
|
||||||
|
void qtest_clock_warp(int64_t dest);
|
||||||
|
|
||||||
/* vl.c */
|
/* vl.c */
|
||||||
extern int smp_cores;
|
extern int smp_cores;
|
||||||
extern int smp_threads;
|
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);
|
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;
|
QEMUTimer **ptimer_head, *ts;
|
||||||
int64_t current_time;
|
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);
|
int qemu_timer_expired(QEMUTimer *timer_head, int64_t current_time);
|
||||||
uint64_t qemu_timer_expire_time_ns(QEMUTimer *ts);
|
uint64_t qemu_timer_expire_time_ns(QEMUTimer *ts);
|
||||||
|
|
||||||
|
void qemu_run_timers(QEMUClock *clock);
|
||||||
void qemu_run_all_timers(void);
|
void qemu_run_all_timers(void);
|
||||||
int qemu_alarm_pending(void);
|
int qemu_alarm_pending(void);
|
||||||
void configure_alarms(char const *opt);
|
void configure_alarms(char const *opt);
|
||||||
|
45
qtest.c
45
qtest.c
@ -18,6 +18,7 @@
|
|||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "hw/irq.h"
|
#include "hw/irq.h"
|
||||||
#include "sysemu.h"
|
#include "sysemu.h"
|
||||||
|
#include "cpus.h"
|
||||||
|
|
||||||
#define MAX_IRQ 256
|
#define MAX_IRQ 256
|
||||||
|
|
||||||
@ -44,6 +45,30 @@ static bool qtest_opened;
|
|||||||
*
|
*
|
||||||
* Valid requests
|
* 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
|
* > outb ADDR VALUE
|
||||||
* < OK
|
* < OK
|
||||||
*
|
*
|
||||||
@ -299,6 +324,25 @@ static void qtest_process_command(CharDriverState *chr, gchar **words)
|
|||||||
|
|
||||||
qtest_send_prefix(chr);
|
qtest_send_prefix(chr);
|
||||||
qtest_send(chr, "OK\n");
|
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 {
|
} else {
|
||||||
qtest_send_prefix(chr);
|
qtest_send_prefix(chr);
|
||||||
qtest_send(chr, "FAIL Unknown command `%s'\n", words[0]);
|
qtest_send(chr, "FAIL Unknown command `%s'\n", words[0]);
|
||||||
@ -377,6 +421,7 @@ int qtest_init(void)
|
|||||||
|
|
||||||
g_assert(qtest_chrdev != NULL);
|
g_assert(qtest_chrdev != NULL);
|
||||||
|
|
||||||
|
configure_icount("0");
|
||||||
chr = qemu_chr_new("qtest", qtest_chrdev, NULL);
|
chr = qemu_chr_new("qtest", qtest_chrdev, NULL);
|
||||||
|
|
||||||
qemu_chr_add_handlers(chr, qtest_can_read, qtest_read, qtest_event, chr);
|
qemu_chr_add_handlers(chr, qtest_can_read, qtest_read, qtest_event, chr);
|
||||||
|
Loading…
Reference in New Issue
Block a user