#include <sys/param.h>
#endif
-#ifdef __linux__
-#include <sys/ioctl.h>
-#include <linux/rtc.h>
-/* For the benefit of older linux systems which don't supply it,
- we use a local copy of hpet.h. */
-/* #include <linux/hpet.h> */
-#include "hpet.h"
-#endif
-
#ifdef _WIN32
#include <windows.h>
#include <mmsystem.h>
}
}
-#ifndef CONFIG_IOTHREAD
-static int64_t qemu_icount_delta(void)
-{
- if (!use_icount) {
- return 5000 * (int64_t) 1000000;
- } else if (use_icount == 1) {
- /* When not using an adaptive execution frequency
- we tend to get badly out of sync with real time,
- so just delay for a reasonable amount of time. */
- return 0;
- } else {
- return cpu_get_icount() - cpu_get_clock();
- }
-}
-#endif
-
/* enable cpu_get_ticks() */
void cpu_enable_ticks(void)
{
int enabled;
QEMUTimer *warp_timer;
+ QEMUTimer *active_timers;
+
+ NotifierList reset_notifiers;
+ int64_t last;
};
struct QEMUTimer {
#ifdef _WIN32
+static int mm_start_timer(struct qemu_alarm_timer *t);
+static void mm_stop_timer(struct qemu_alarm_timer *t);
+static void mm_rearm_timer(struct qemu_alarm_timer *t);
+
static int win32_start_timer(struct qemu_alarm_timer *t);
static void win32_stop_timer(struct qemu_alarm_timer *t);
static void win32_rearm_timer(struct qemu_alarm_timer *t);
static int unix_start_timer(struct qemu_alarm_timer *t);
static void unix_stop_timer(struct qemu_alarm_timer *t);
+static void unix_rearm_timer(struct qemu_alarm_timer *t);
#ifdef __linux__
static void dynticks_stop_timer(struct qemu_alarm_timer *t);
static void dynticks_rearm_timer(struct qemu_alarm_timer *t);
-static int hpet_start_timer(struct qemu_alarm_timer *t);
-static void hpet_stop_timer(struct qemu_alarm_timer *t);
-
-static int rtc_start_timer(struct qemu_alarm_timer *t);
-static void rtc_stop_timer(struct qemu_alarm_timer *t);
-
#endif /* __linux__ */
#endif /* _WIN32 */
int64_t delta;
static int64_t last_delta;
/* If the VM is not running, then do nothing. */
- if (!vm_running)
+ if (!runstate_is_running())
return;
cur_time = cpu_get_clock();
#ifdef __linux__
{"dynticks", dynticks_start_timer,
dynticks_stop_timer, dynticks_rearm_timer},
- /* HPET - if available - is preferred */
- {"hpet", hpet_start_timer, hpet_stop_timer, NULL},
- /* ...otherwise try RTC */
- {"rtc", rtc_start_timer, rtc_stop_timer, NULL},
#endif
- {"unix", unix_start_timer, unix_stop_timer, NULL},
+ {"unix", unix_start_timer, unix_stop_timer, unix_rearm_timer},
#else
+ {"mmtimer", mm_start_timer, mm_stop_timer, NULL},
+ {"mmtimer2", mm_start_timer, mm_stop_timer, mm_rearm_timer},
{"dynticks", win32_start_timer, win32_stop_timer, win32_rearm_timer},
{"win32", win32_start_timer, win32_stop_timer, NULL},
#endif
exit(0);
}
- arg = qemu_strdup(opt);
+ arg = g_strdup(opt);
/* Reorder the array */
name = strtok(arg, ",");
name = strtok(NULL, ",");
}
- qemu_free(arg);
+ g_free(arg);
if (cur) {
/* Disable remaining timers */
}
}
-#define QEMU_NUM_CLOCKS 3
-
QEMUClock *rt_clock;
QEMUClock *vm_clock;
QEMUClock *host_clock;
-static QEMUTimer *active_timers[QEMU_NUM_CLOCKS];
-
static QEMUClock *qemu_new_clock(int type)
{
QEMUClock *clock;
- clock = qemu_mallocz(sizeof(QEMUClock));
+
+ clock = g_malloc0(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;
}
return;
}
- if (vm_running) {
+ if (runstate_is_running()) {
int64_t clock = qemu_get_clock_ns(rt_clock);
int64_t warp_delta = clock - vm_clock_warp_start;
if (use_icount == 1) {
int64_t delta = cur_time - cur_icount;
qemu_icount_bias += MIN(warp_delta, delta);
}
- if (qemu_timer_expired(active_timers[QEMU_CLOCK_VIRTUAL],
+ if (qemu_timer_expired(vm_clock->active_timers,
qemu_get_clock_ns(vm_clock))) {
qemu_notify_event();
}
* the earliest vm_clock timer.
*/
icount_warp_rt(NULL);
- if (!all_cpu_threads_idle() || !active_timers[clock->type]) {
+ if (!all_cpu_threads_idle() || !clock->active_timers) {
qemu_del_timer(clock->warp_timer);
return;
}
{
QEMUTimer *ts;
- ts = qemu_mallocz(sizeof(QEMUTimer));
+ ts = g_malloc0(sizeof(QEMUTimer));
ts->clock = clock;
ts->cb = cb;
ts->opaque = opaque;
void qemu_free_timer(QEMUTimer *ts)
{
- qemu_free(ts);
+ g_free(ts);
}
/* stop a timer, but do not dealloc it */
/* NOTE: this code must be signal safe because
qemu_timer_expired() can be called from a signal. */
- pt = &active_timers[ts->clock->type];
+ pt = &ts->clock->active_timers;
for(;;) {
t = *pt;
if (!t)
/* add the timer in the sorted list */
/* NOTE: this code must be signal safe because
qemu_timer_expired() can be called from a signal. */
- pt = &active_timers[ts->clock->type];
+ pt = &ts->clock->active_timers;
for(;;) {
t = *pt;
if (!qemu_timer_expired_ns(t, expire_time)) {
*pt = ts;
/* Rearm if necessary */
- if (pt == &active_timers[ts->clock->type]) {
+ if (pt == &ts->clock->active_timers) {
if (!alarm_timer->pending) {
qemu_rearm_alarm_timer(alarm_timer);
}
int qemu_timer_pending(QEMUTimer *ts)
{
QEMUTimer *t;
- for(t = active_timers[ts->clock->type]; t != NULL; t = t->next) {
+ for (t = ts->clock->active_timers; t != NULL; t = t->next) {
if (t == ts)
return 1;
}
return;
current_time = qemu_get_clock_ns(clock);
- ptimer_head = &active_timers[clock->type];
+ ptimer_head = &clock->active_timers;
for(;;) {
ts = *ptimer_head;
if (!qemu_timer_expired_ns(ts, current_time)) {
int64_t qemu_get_clock_ns(QEMUClock *clock)
{
+ int64_t now, last;
+
switch(clock->type) {
case QEMU_CLOCK_REALTIME:
return get_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);
if (!option)
return;
-#ifdef CONFIG_IOTHREAD
vm_clock->warp_timer = qemu_new_timer_ns(rt_clock, icount_warp_rt, NULL);
-#endif
if (strcmp(option, "auto") != 0) {
icount_time_shift = strtol(option, NULL, 0);
}
/* vm time timers */
- if (vm_running) {
+ if (runstate_is_running()) {
qemu_run_timers(vm_clock);
}
int64_t delta = INT32_MAX;
assert(use_icount);
- if (active_timers[QEMU_CLOCK_VIRTUAL]) {
- delta = active_timers[QEMU_CLOCK_VIRTUAL]->expire_time -
+ if (vm_clock->active_timers) {
+ delta = vm_clock->active_timers->expire_time -
qemu_get_clock_ns(vm_clock);
}
int64_t delta;
int64_t rtdelta;
- if (!use_icount && active_timers[QEMU_CLOCK_VIRTUAL]) {
- delta = active_timers[QEMU_CLOCK_VIRTUAL]->expire_time -
+ if (!use_icount && vm_clock->active_timers) {
+ delta = vm_clock->active_timers->expire_time -
qemu_get_clock_ns(vm_clock);
} else {
delta = INT32_MAX;
}
- if (active_timers[QEMU_CLOCK_HOST]) {
- int64_t hdelta = active_timers[QEMU_CLOCK_HOST]->expire_time -
+ if (host_clock->active_timers) {
+ int64_t hdelta = host_clock->active_timers->expire_time -
qemu_get_clock_ns(host_clock);
if (hdelta < delta)
delta = hdelta;
}
- if (active_timers[QEMU_CLOCK_REALTIME]) {
- rtdelta = (active_timers[QEMU_CLOCK_REALTIME]->expire_time -
+ if (rt_clock->active_timers) {
+ rtdelta = (rt_clock->active_timers->expire_time -
qemu_get_clock_ns(rt_clock));
if (rtdelta < delta)
delta = rtdelta;
#if defined(__linux__)
-#define RTC_FREQ 1024
-
-static void enable_sigio_timer(int fd)
-{
- struct sigaction act;
-
- /* timer signal */
- sigfillset(&act.sa_mask);
- act.sa_flags = 0;
- act.sa_handler = host_alarm_handler;
-
- sigaction(SIGIO, &act, NULL);
- fcntl_setfl(fd, O_ASYNC);
- fcntl(fd, F_SETOWN, getpid());
-}
-
-static int hpet_start_timer(struct qemu_alarm_timer *t)
-{
- struct hpet_info info;
- int r, fd;
-
- fd = qemu_open("/dev/hpet", O_RDONLY);
- if (fd < 0)
- return -1;
-
- /* Set frequency */
- r = ioctl(fd, HPET_IRQFREQ, RTC_FREQ);
- if (r < 0) {
- fprintf(stderr, "Could not configure '/dev/hpet' to have a 1024Hz timer. This is not a fatal\n"
- "error, but for better emulation accuracy type:\n"
- "'echo 1024 > /proc/sys/dev/hpet/max-user-freq' as root.\n");
- goto fail;
- }
-
- /* Check capabilities */
- r = ioctl(fd, HPET_INFO, &info);
- if (r < 0)
- goto fail;
-
- /* Enable periodic mode */
- r = ioctl(fd, HPET_EPI, 0);
- if (info.hi_flags && (r < 0))
- goto fail;
-
- /* Enable interrupt */
- r = ioctl(fd, HPET_IE_ON, 0);
- if (r < 0)
- goto fail;
-
- enable_sigio_timer(fd);
- t->fd = fd;
-
- return 0;
-fail:
- close(fd);
- return -1;
-}
-
-static void hpet_stop_timer(struct qemu_alarm_timer *t)
-{
- int fd = t->fd;
-
- close(fd);
-}
-
-static int rtc_start_timer(struct qemu_alarm_timer *t)
-{
- int rtc_fd;
- unsigned long current_rtc_freq = 0;
-
- TFR(rtc_fd = qemu_open("/dev/rtc", O_RDONLY));
- if (rtc_fd < 0)
- return -1;
- ioctl(rtc_fd, RTC_IRQP_READ, ¤t_rtc_freq);
- if (current_rtc_freq != RTC_FREQ &&
- ioctl(rtc_fd, RTC_IRQP_SET, RTC_FREQ) < 0) {
- fprintf(stderr, "Could not configure '/dev/rtc' to have a 1024 Hz timer. This is not a fatal\n"
- "error, but for better emulation accuracy either use a 2.6 host Linux kernel or\n"
- "type 'echo 1024 > /proc/sys/dev/rtc/max-user-freq' as root.\n");
- goto fail;
- }
- if (ioctl(rtc_fd, RTC_PIE_ON, 0) < 0) {
- fail:
- close(rtc_fd);
- return -1;
- }
-
- enable_sigio_timer(rtc_fd);
-
- t->fd = rtc_fd;
-
- return 0;
-}
-
-static void rtc_stop_timer(struct qemu_alarm_timer *t)
-{
- int rtc_fd = t->fd;
-
- close(rtc_fd);
-}
+#include "compatfd.h"
static int dynticks_start_timer(struct qemu_alarm_timer *t)
{
memset(&ev, 0, sizeof(ev));
ev.sigev_value.sival_int = 0;
ev.sigev_notify = SIGEV_SIGNAL;
+#ifdef SIGEV_THREAD_ID
+ if (qemu_signalfd_available()) {
+ ev.sigev_notify = SIGEV_THREAD_ID;
+ ev._sigev_un._tid = qemu_get_thread_id();
+ }
+#endif /* SIGEV_THREAD_ID */
ev.sigev_signo = SIGALRM;
if (timer_create(CLOCK_REALTIME, &ev, &host_timer)) {
int64_t current_ns;
assert(alarm_has_dynticks(t));
- if (!active_timers[QEMU_CLOCK_REALTIME] &&
- !active_timers[QEMU_CLOCK_VIRTUAL] &&
- !active_timers[QEMU_CLOCK_HOST])
+ if (!rt_clock->active_timers &&
+ !vm_clock->active_timers &&
+ !host_clock->active_timers)
return;
nearest_delta_ns = qemu_next_alarm_deadline();
static int unix_start_timer(struct qemu_alarm_timer *t)
{
struct sigaction act;
- struct itimerval itv;
- int err;
/* timer signal */
sigfillset(&act.sa_mask);
act.sa_handler = host_alarm_handler;
sigaction(SIGALRM, &act, NULL);
+ return 0;
+}
- itv.it_interval.tv_sec = 0;
- /* for i386 kernel 2.6 to get 1 ms */
- itv.it_interval.tv_usec = 999;
- itv.it_value.tv_sec = 0;
- itv.it_value.tv_usec = 10 * 1000;
+static void unix_rearm_timer(struct qemu_alarm_timer *t)
+{
+ struct itimerval itv;
+ int64_t nearest_delta_ns = INT64_MAX;
+ int err;
- err = setitimer(ITIMER_REAL, &itv, NULL);
- if (err)
- return -1;
+ assert(alarm_has_dynticks(t));
+ if (!rt_clock->active_timers &&
+ !vm_clock->active_timers &&
+ !host_clock->active_timers)
+ return;
- return 0;
+ nearest_delta_ns = qemu_next_alarm_deadline();
+ if (nearest_delta_ns < MIN_TIMER_REARM_NS)
+ nearest_delta_ns = MIN_TIMER_REARM_NS;
+
+ itv.it_interval.tv_sec = 0;
+ itv.it_interval.tv_usec = 0; /* 0 for one-shot timer */
+ itv.it_value.tv_sec = nearest_delta_ns / 1000000000;
+ itv.it_value.tv_usec = (nearest_delta_ns % 1000000000) / 1000;
+ err = setitimer(ITIMER_REAL, &itv, NULL);
+ if (err) {
+ perror("setitimer");
+ fprintf(stderr, "Internal timer error: aborting\n");
+ exit(1);
+ }
}
static void unix_stop_timer(struct qemu_alarm_timer *t)
#ifdef _WIN32
+static MMRESULT mm_timer;
+static unsigned mm_period;
+
+static void CALLBACK mm_alarm_handler(UINT uTimerID, UINT uMsg,
+ DWORD_PTR dwUser, DWORD_PTR dw1,
+ DWORD_PTR dw2)
+{
+ struct qemu_alarm_timer *t = alarm_timer;
+ if (!t) {
+ return;
+ }
+ if (alarm_has_dynticks(t) || qemu_next_alarm_deadline() <= 0) {
+ t->expired = alarm_has_dynticks(t);
+ t->pending = 1;
+ qemu_notify_event();
+ }
+}
+
+static int mm_start_timer(struct qemu_alarm_timer *t)
+{
+ TIMECAPS tc;
+ UINT flags;
+
+ memset(&tc, 0, sizeof(tc));
+ timeGetDevCaps(&tc, sizeof(tc));
+
+ mm_period = tc.wPeriodMin;
+ timeBeginPeriod(mm_period);
+
+ flags = TIME_CALLBACK_FUNCTION;
+ if (alarm_has_dynticks(t)) {
+ flags |= TIME_ONESHOT;
+ } else {
+ flags |= TIME_PERIODIC;
+ }
+
+ mm_timer = timeSetEvent(1, /* interval (ms) */
+ mm_period, /* resolution */
+ mm_alarm_handler, /* function */
+ (DWORD_PTR)t, /* parameter */
+ flags);
+
+ if (!mm_timer) {
+ fprintf(stderr, "Failed to initialize win32 alarm timer: %ld\n",
+ GetLastError());
+ timeEndPeriod(mm_period);
+ return -1;
+ }
+
+ return 0;
+}
+
+static void mm_stop_timer(struct qemu_alarm_timer *t)
+{
+ timeKillEvent(mm_timer);
+ timeEndPeriod(mm_period);
+}
+
+static void mm_rearm_timer(struct qemu_alarm_timer *t)
+{
+ int nearest_delta_ms;
+
+ assert(alarm_has_dynticks(t));
+ if (!rt_clock->active_timers &&
+ !vm_clock->active_timers &&
+ !host_clock->active_timers) {
+ return;
+ }
+
+ timeKillEvent(mm_timer);
+
+ nearest_delta_ms = (qemu_next_alarm_deadline() + 999999) / 1000000;
+ if (nearest_delta_ms < 1) {
+ nearest_delta_ms = 1;
+ }
+ mm_timer = timeSetEvent(nearest_delta_ms,
+ mm_period,
+ mm_alarm_handler,
+ (DWORD_PTR)t,
+ TIME_ONESHOT | TIME_CALLBACK_FUNCTION);
+
+ if (!mm_timer) {
+ fprintf(stderr, "Failed to re-arm win32 alarm timer %ld\n",
+ GetLastError());
+
+ timeEndPeriod(mm_period);
+ exit(1);
+ }
+}
+
static int win32_start_timer(struct qemu_alarm_timer *t)
{
HANDLE hTimer;
BOOLEAN success;
assert(alarm_has_dynticks(t));
- if (!active_timers[QEMU_CLOCK_REALTIME] &&
- !active_timers[QEMU_CLOCK_VIRTUAL] &&
- !active_timers[QEMU_CLOCK_HOST])
+ if (!rt_clock->active_timers &&
+ !vm_clock->active_timers &&
+ !host_clock->active_timers)
return;
nearest_delta_ms = (qemu_next_alarm_deadline() + 999999) / 1000000;
#endif /* _WIN32 */
-static void alarm_timer_on_change_state_rearm(void *opaque, int running, int reason)
+static void alarm_timer_on_change_state_rearm(void *opaque, int running,
+ RunState state)
{
if (running)
qemu_rearm_alarm_timer((struct qemu_alarm_timer *) opaque);
int qemu_calculate_timeout(void)
{
-#ifndef CONFIG_IOTHREAD
- int timeout;
-
- if (!vm_running)
- timeout = 5000;
- else {
- /* XXX: use timeout computed from timers */
- int64_t add;
- int64_t delta;
- /* Advance virtual time to the next event. */
- delta = qemu_icount_delta();
- if (delta > 0) {
- /* If virtual time is ahead of real time then just
- wait for IO. */
- timeout = (delta + 999999) / 1000000;
- } else {
- /* Wait for either IO to occur or the next
- timer event. */
- add = qemu_next_icount_deadline();
- /* We advance the timer before checking for IO.
- Limit the amount we advance so that early IO
- activity won't get the guest too far ahead. */
- if (add > 10000000)
- add = 10000000;
- delta += add;
- qemu_icount += qemu_icount_round (add);
- timeout = delta / 1000000;
- if (timeout < 0)
- timeout = 0;
- }
- }
-
- return timeout;
-#else /* CONFIG_IOTHREAD */
return 1000;
-#endif
}