summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--qemu-timer.h7
-rw-r--r--vl.c46
2 files changed, 42 insertions, 11 deletions
diff --git a/qemu-timer.h b/qemu-timer.h
index e44c33420f..e7eaa0436c 100644
--- a/qemu-timer.h
+++ b/qemu-timer.h
@@ -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);
diff --git a/vl.c b/vl.c
index c4133f3562..bf592ec18c 100644
--- a/vl.c
+++ b/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();