diff --git a/qemu-timer.c b/qemu-timer.c index 67c2974959..f95374c7c1 100644 --- a/qemu-timer.c +++ b/qemu-timer.c @@ -150,6 +150,9 @@ struct QEMUClock { int enabled; QEMUTimer *warp_timer; + + NotifierList reset_notifiers; + int64_t last; }; struct QEMUTimer { @@ -376,9 +379,15 @@ static QEMUTimer *active_timers[QEMU_NUM_CLOCKS]; static QEMUClock *qemu_new_clock(int type) { QEMUClock *clock; + clock = qemu_mallocz(sizeof(QEMUClock)); clock->type = type; clock->enabled = 1; + notifier_list_init(&clock->reset_notifiers); + /* required to detect & report backward jumps */ + if (type == QEMU_CLOCK_HOST) { + clock->last = get_clock_realtime(); + } return clock; } @@ -593,6 +602,8 @@ static void qemu_run_timers(QEMUClock *clock) int64_t qemu_get_clock_ns(QEMUClock *clock) { + int64_t now, last; + switch(clock->type) { case QEMU_CLOCK_REALTIME: return get_clock(); @@ -604,10 +615,26 @@ int64_t qemu_get_clock_ns(QEMUClock *clock) return cpu_get_clock(); } case QEMU_CLOCK_HOST: - return get_clock_realtime(); + now = get_clock_realtime(); + last = clock->last; + clock->last = now; + if (now < last) { + notifier_list_notify(&clock->reset_notifiers, &now); + } + return now; } } +void qemu_register_clock_reset_notifier(QEMUClock *clock, Notifier *notifier) +{ + notifier_list_add(&clock->reset_notifiers, notifier); +} + +void qemu_unregister_clock_reset_notifier(QEMUClock *clock, Notifier *notifier) +{ + notifier_list_remove(&clock->reset_notifiers, notifier); +} + void init_clocks(void) { rt_clock = qemu_new_clock(QEMU_CLOCK_REALTIME); diff --git a/qemu-timer.h b/qemu-timer.h index 06cbe20914..0a43469847 100644 --- a/qemu-timer.h +++ b/qemu-timer.h @@ -2,6 +2,7 @@ #define QEMU_TIMER_H #include "qemu-common.h" +#include "notify.h" #include #include @@ -40,6 +41,10 @@ int64_t qemu_get_clock_ns(QEMUClock *clock); void qemu_clock_enable(QEMUClock *clock, int enabled); void qemu_clock_warp(QEMUClock *clock); +void qemu_register_clock_reset_notifier(QEMUClock *clock, Notifier *notifier); +void qemu_unregister_clock_reset_notifier(QEMUClock *clock, + Notifier *notifier); + QEMUTimer *qemu_new_timer(QEMUClock *clock, int scale, QEMUTimerCB *cb, void *opaque); void qemu_free_timer(QEMUTimer *ts);