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