Introduce QEMU_CLOCK_HOST
Despite its name QEMU_CLOCK_REALTIME is (normally) not using CLOCK_REALTIME / the host system time as base. In order to allow also non-trivial RTC emulations (MC146818) to follow the host time instead of the virtual guest time, introduce the new clock type QEMU_CLOCK_HOST. It is unconditionally based on CLOCK_REALTIME, thus will follow system time changes of the host. The only limitation of its current implementation is that pending host_clock timers may not fire early if the host time is pushed forward beyond their expiry. So far no urgent need to overcome this limitation was identified, so it's left as simple as it is (expiry on next alarm timer tick). Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
This commit is contained in:
parent
f64382bad8
commit
21d5d12bb0
@ -17,6 +17,13 @@ extern QEMUClock *rt_clock;
|
||||
precision clock, usually cpu cycles (use ticks_per_sec). */
|
||||
extern QEMUClock *vm_clock;
|
||||
|
||||
/* The host clock should be use for device models that emulate accurate
|
||||
real time sources. It will continue to run when the virtual machine
|
||||
is suspended, and it will reflect system time changes the host may
|
||||
undergo (e.g. due to NTP). The host clock has the same precision as
|
||||
the virtual clock. */
|
||||
extern QEMUClock *host_clock;
|
||||
|
||||
int64_t qemu_get_clock(QEMUClock *clock);
|
||||
|
||||
QEMUTimer *qemu_new_timer(QEMUClock *clock, QEMUTimerCB *cb, void *opaque);
|
||||
|
46
vl.c
46
vl.c
@ -531,6 +531,14 @@ uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c)
|
||||
/***********************************************************/
|
||||
/* real time host monotonic timer */
|
||||
|
||||
static int64_t get_clock_realtime(void)
|
||||
{
|
||||
struct timeval tv;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
return tv.tv_sec * 1000000000LL + (tv.tv_usec * 1000);
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
static int64_t clock_freq;
|
||||
@ -585,9 +593,7 @@ static int64_t get_clock(void)
|
||||
{
|
||||
/* XXX: using gettimeofday leads to problems if the date
|
||||
changes, so it should be avoided. */
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
return tv.tv_sec * 1000000000LL + (tv.tv_usec * 1000);
|
||||
return get_clock_realtime();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -678,6 +684,7 @@ void cpu_disable_ticks(void)
|
||||
|
||||
#define QEMU_CLOCK_REALTIME 0
|
||||
#define QEMU_CLOCK_VIRTUAL 1
|
||||
#define QEMU_CLOCK_HOST 2
|
||||
|
||||
struct QEMUClock {
|
||||
int type;
|
||||
@ -904,10 +911,13 @@ next:
|
||||
}
|
||||
}
|
||||
|
||||
#define QEMU_NUM_CLOCKS 3
|
||||
|
||||
QEMUClock *rt_clock;
|
||||
QEMUClock *vm_clock;
|
||||
QEMUClock *host_clock;
|
||||
|
||||
static QEMUTimer *active_timers[2];
|
||||
static QEMUTimer *active_timers[QEMU_NUM_CLOCKS];
|
||||
|
||||
static QEMUClock *qemu_new_clock(int type)
|
||||
{
|
||||
@ -1034,6 +1044,8 @@ int64_t qemu_get_clock(QEMUClock *clock)
|
||||
} else {
|
||||
return cpu_get_clock();
|
||||
}
|
||||
case QEMU_CLOCK_HOST:
|
||||
return get_clock_realtime();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1042,6 +1054,7 @@ static void init_clocks(void)
|
||||
init_get_clock();
|
||||
rt_clock = qemu_new_clock(QEMU_CLOCK_REALTIME);
|
||||
vm_clock = qemu_new_clock(QEMU_CLOCK_VIRTUAL);
|
||||
host_clock = qemu_new_clock(QEMU_CLOCK_HOST);
|
||||
}
|
||||
|
||||
/* save a timer */
|
||||
@ -1126,7 +1139,9 @@ static void host_alarm_handler(int host_signum)
|
||||
qemu_timer_expired(active_timers[QEMU_CLOCK_VIRTUAL],
|
||||
qemu_get_clock(vm_clock))) ||
|
||||
qemu_timer_expired(active_timers[QEMU_CLOCK_REALTIME],
|
||||
qemu_get_clock(rt_clock))) {
|
||||
qemu_get_clock(rt_clock)) ||
|
||||
qemu_timer_expired(active_timers[QEMU_CLOCK_HOST],
|
||||
qemu_get_clock(host_clock))) {
|
||||
qemu_event_increment();
|
||||
if (alarm_timer) alarm_timer->flags |= ALARM_FLAG_EXPIRED;
|
||||
|
||||
@ -1143,14 +1158,18 @@ static void host_alarm_handler(int host_signum)
|
||||
|
||||
static int64_t qemu_next_deadline(void)
|
||||
{
|
||||
int64_t delta;
|
||||
/* To avoid problems with overflow limit this to 2^32. */
|
||||
int64_t delta = INT32_MAX;
|
||||
|
||||
if (active_timers[QEMU_CLOCK_VIRTUAL]) {
|
||||
delta = active_timers[QEMU_CLOCK_VIRTUAL]->expire_time -
|
||||
qemu_get_clock(vm_clock);
|
||||
} else {
|
||||
/* To avoid problems with overflow limit this to 2^32. */
|
||||
delta = INT32_MAX;
|
||||
}
|
||||
if (active_timers[QEMU_CLOCK_HOST]) {
|
||||
int64_t hdelta = active_timers[QEMU_CLOCK_HOST]->expire_time -
|
||||
qemu_get_clock(host_clock);
|
||||
if (hdelta < delta)
|
||||
delta = hdelta;
|
||||
}
|
||||
|
||||
if (delta < 0)
|
||||
@ -1354,7 +1373,8 @@ static void dynticks_rearm_timer(struct qemu_alarm_timer *t)
|
||||
int64_t current_us;
|
||||
|
||||
if (!active_timers[QEMU_CLOCK_REALTIME] &&
|
||||
!active_timers[QEMU_CLOCK_VIRTUAL])
|
||||
!active_timers[QEMU_CLOCK_VIRTUAL] &&
|
||||
!active_timers[QEMU_CLOCK_HOST])
|
||||
return;
|
||||
|
||||
nearest_delta_us = qemu_next_deadline_dyntick();
|
||||
@ -1470,7 +1490,8 @@ static void win32_rearm_timer(struct qemu_alarm_timer *t)
|
||||
struct qemu_alarm_win32 *data = t->priv;
|
||||
|
||||
if (!active_timers[QEMU_CLOCK_REALTIME] &&
|
||||
!active_timers[QEMU_CLOCK_VIRTUAL])
|
||||
!active_timers[QEMU_CLOCK_VIRTUAL] &&
|
||||
!active_timers[QEMU_CLOCK_HOST])
|
||||
return;
|
||||
|
||||
timeKillEvent(data->timerId);
|
||||
@ -3916,6 +3937,9 @@ void main_loop_wait(int timeout)
|
||||
qemu_run_timers(&active_timers[QEMU_CLOCK_REALTIME],
|
||||
qemu_get_clock(rt_clock));
|
||||
|
||||
qemu_run_timers(&active_timers[QEMU_CLOCK_HOST],
|
||||
qemu_get_clock(host_clock));
|
||||
|
||||
/* Check bottom-halves last in case any of the earlier events triggered
|
||||
them. */
|
||||
qemu_bh_poll();
|
||||
|
Loading…
Reference in New Issue
Block a user