#include "vl.h" #include #include #include "android_utils.h" #include "android.h" #include #define D(...) VERBOSE_PRINT(init,__VA_ARGS__) #ifdef _WIN32 #include #else #include #endif #ifdef __linux__ #include #include "hpet.h" #endif #define TFR(expr) do { if ((expr) != -1) break; } while (errno == EINTR) QEMUClock *rt_clock; QEMUClock *vm_clock; /***********************************************************/ /* real time host monotonic timer */ /* digit: the following two variables are used to implement high-resolution * poll-based interrupts. the idea is to be able to generate an emulated * interrupt every millisecond, even on non-Linux platforms which don't have * a /dev/rtc */ static int64_t milli_last_ns; static int64_t milli_next_ns; /* digit: the following global boolean is set when we need to perform * high-resolution polling. If not, we'll use host interrupts instead */ int qemu_milli_needed = 0; #ifdef WIN32 static int64_t clock_freq; static void init_get_clock(void) { LARGE_INTEGER freq; int ret; ret = QueryPerformanceFrequency(&freq); if (ret == 0) { fprintf(stderr, "Could not calibrate ticks\n"); exit(1); } clock_freq = freq.QuadPart; { LARGE_INTEGER ti; QueryPerformanceCounter(&ti); milli_last_ns = muldiv64(ti.QuadPart,QEMU_TIMER_BASE,clock_freq); milli_next_ns = milli_last_ns + 1000000; } } static int64_t get_clock(void) { LARGE_INTEGER ti; QueryPerformanceCounter(&ti); return muldiv64(ti.QuadPart, QEMU_TIMER_BASE, clock_freq); } #elif defined(__APPLE__) #include static mach_timebase_info_data_t _mach_timebase_info; static int64_t _mach_timebase; static int64_t get_clock(void) { int64_t elapsed = mach_absolute_time() - _mach_timebase; int64_t numer = _mach_timebase_info.numer; int64_t denom = _mach_timebase_info.denom; /* return elapsed time in nanoseconds */ return elapsed * numer / denom; } static void init_get_clock(void) { mach_timebase_info( &_mach_timebase_info ); _mach_timebase = mach_absolute_time(); milli_last_ns = get_clock(); milli_next_ns = milli_last_ns + 1000000; } #else static int use_rt_clock; static int64_t get_clock(void) { #if defined(__linux__) if (use_rt_clock) { struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); return ts.tv_sec * 1000000000LL + ts.tv_nsec; } else #endif { /* 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); } } static void init_get_clock(void) { use_rt_clock = 0; #if defined(__linux__) { struct timespec ts; if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) { use_rt_clock = 1; } } #endif milli_last_ns = get_clock(); milli_next_ns = milli_last_ns + 1000000; } #endif int64_t qemu_get_elapsed_ns(void) { return get_clock(); } void qemu_polling_enable( void ) { if (++qemu_milli_needed == 1) { milli_last_ns = get_clock(); milli_next_ns = milli_last_ns + 1000000; } } void qemu_polling_disable( void ) { --qemu_milli_needed; } int qemu_milli_check(void) { int result = 0; int64_t now_ns = get_clock(); //fprintf(stderr,"MilliCheck: now=%.4fms next=%.4fms\n", (double)now_ns/1000000.0, (double)milli_next_ns/1000000.0); if (now_ns < milli_last_ns) { /* software suspend ? */ milli_last_ns = now_ns; milli_next_ns = now_ns + 1000000; return 1; } while (now_ns >= milli_next_ns) { milli_last_ns = milli_next_ns; milli_next_ns = milli_last_ns + 1000000; result += 1; } return result; } /***********************************************************/ /* guest cycle counter */ static int64_t cpu_ticks_prev; static int64_t cpu_ticks_offset; static int64_t cpu_clock_offset; static int cpu_ticks_enabled; /* return the host CPU cycle counter and handle stop/restart */ int64_t cpu_get_ticks(void) { if (!cpu_ticks_enabled) { return cpu_ticks_offset; } else { int64_t ticks; ticks = cpu_get_real_ticks(); if (cpu_ticks_prev > ticks) { /* Note: non increasing ticks may happen if the host uses software suspend */ cpu_ticks_offset += cpu_ticks_prev - ticks; } cpu_ticks_prev = ticks; return ticks + cpu_ticks_offset; } } /* return the host CPU monotonic timer and handle stop/restart */ static int64_t cpu_get_clock(void) { int64_t ti; if (!cpu_ticks_enabled) { return cpu_clock_offset; } else { ti = get_clock(); return ti + cpu_clock_offset; } } /* enable cpu_get_ticks() */ void cpu_enable_ticks(void) { if (!cpu_ticks_enabled) { cpu_ticks_offset -= cpu_get_real_ticks(); cpu_clock_offset -= get_clock(); cpu_ticks_enabled = 1; } } /* disable cpu_get_ticks() : the clock is stopped. You must not call cpu_get_ticks() after that. */ void cpu_disable_ticks(void) { if (cpu_ticks_enabled) { cpu_ticks_offset = cpu_get_ticks(); cpu_clock_offset = cpu_get_clock(); cpu_ticks_enabled = 0; } } /***********************************************************/ /* timers */ #define QEMU_TIMER_REALTIME 0 #define QEMU_TIMER_VIRTUAL 1 struct QEMUClock { int type; /* XXX: add frequency */ }; struct QEMUTimer { QEMUClock *clock; int64_t expire_time; QEMUTimerCB *cb; void *opaque; struct QEMUTimer *next; }; struct qemu_alarm_timer { char const *name; unsigned int flags; int (*start)(struct qemu_alarm_timer *t); void (*stop)(struct qemu_alarm_timer *t); void (*rearm)(struct qemu_alarm_timer *t); void (*signal)(void); void *priv; }; #define ALARM_FLAG_DYNTICKS 0x1 #define ALARM_FLAG_EXPIRED 0x2 static inline int alarm_timer_has_dynticks(struct qemu_alarm_timer *t) { return t && t->flags & ALARM_FLAG_DYNTICKS; } static void alarm_timer_rearm(struct qemu_alarm_timer *t) { if (!alarm_timer_has_dynticks(t)) return; t->rearm(t); } /* TODO: MIN_TIMER_REARM_US should be optimized */ #define MIN_TIMER_REARM_US 250 static struct qemu_alarm_timer *alarm_timer; #ifdef _WIN32 #define USE_WIN32_TIMER 1 #define USE_WIN32_DYNTICKS_TIMER 1 #else #define USE_UNIX_TIMER 1 #endif #ifdef __linux__ #define DONT_USE_DYNTICKS_TIMER 1 /* it freezes the Android emulator hard */ #define USE_HPET_TIMER 1 #define USE_RTC_TIMER 1 #endif #if defined(USE_WIN32_TIMER) || defined(USE_WIN32_DYNTICKS_TIMER) struct qemu_alarm_win32 { MMRESULT timerId; HANDLE host_alarm; unsigned int period; } alarm_win32_data = {0, NULL, -1}; static int win32_start_timer(struct qemu_alarm_timer *t); static void win32_stop_timer(struct qemu_alarm_timer *t); #endif #ifdef USE_WIN32_DYNTICKS_TIMER static void win32_rearm_timer(struct qemu_alarm_timer *t); #endif #ifdef USE_UNIX_TIMER static int unix_start_timer(struct qemu_alarm_timer *t); static void unix_stop_timer(struct qemu_alarm_timer *t); #endif #ifdef USE_DYNTICKS_TIMER static int dynticks_start_timer(struct qemu_alarm_timer *t); static void dynticks_stop_timer(struct qemu_alarm_timer *t); static void dynticks_rearm_timer(struct qemu_alarm_timer *t); #endif #ifdef USE_HPET_TIMER static int hpet_start_timer(struct qemu_alarm_timer *t); static void hpet_stop_timer(struct qemu_alarm_timer *t); #endif #ifdef USE_RTC_TIMER static int rtc_start_timer(struct qemu_alarm_timer *t); static void rtc_stop_timer(struct qemu_alarm_timer *t); #endif static struct qemu_alarm_timer alarm_timers[] = { #ifdef USE_DYNTICKS_TIMER {"dynticks", ALARM_FLAG_DYNTICKS, dynticks_start_timer, dynticks_stop_timer, dynticks_rearm_timer, NULL, NULL}, #endif #ifdef USE_HPET_TIMER /* HPET - if available - is preferred */ {"hpet", 0, hpet_start_timer, hpet_stop_timer, NULL, NULL, NULL}, #endif #ifdef USE_RTC_TIMER /* ...otherwise try RTC */ {"rtc", 0, rtc_start_timer, rtc_stop_timer, NULL, NULL, NULL}, #endif #ifdef USE_UNIX_TIMER {"unix", 0, unix_start_timer, unix_stop_timer, NULL, NULL, NULL}, #endif #ifdef USE_WIN32_DYNTICKS_TIMER {"dynticks", ALARM_FLAG_DYNTICKS, win32_start_timer, win32_stop_timer, win32_rearm_timer, NULL, &alarm_win32_data}, #endif #ifdef USE_WIN32_TIMER {"win32", 0, win32_start_timer, win32_stop_timer, NULL, NULL, &alarm_win32_data}, #endif {NULL, } }; static void show_available_alarms() { int i; printf("Available alarm timers, in order of precedence:\n"); for (i = 0; alarm_timers[i].name; i++) printf("%s\n", alarm_timers[i].name); } void qemu_configure_alarms(char const *opt) { int i; int cur = 0; int count = (sizeof(alarm_timers) / sizeof(*alarm_timers)) - 1; char *arg; char *name; if (!strcmp(opt, "help")) { show_available_alarms(); exit(0); } arg = strdup(opt); /* Reorder the array */ name = strtok(arg, ","); while (name) { struct qemu_alarm_timer tmp; for (i = 0; i < count && alarm_timers[i].name; i++) { if (!strcmp(alarm_timers[i].name, name)) break; } if (i == count) { fprintf(stderr, "Unknown clock %s\n", name); goto next; } if (i < cur) /* Ignore */ goto next; /* Swap */ tmp = alarm_timers[i]; alarm_timers[i] = alarm_timers[cur]; alarm_timers[cur] = tmp; cur++; next: name = strtok(NULL, ","); } free(arg); if (cur) { /* Disable remaining timers */ for (i = cur; i < count; i++) alarm_timers[i].name = NULL; } /* debug */ show_available_alarms(); } QEMUClock *rt_clock; QEMUClock *vm_clock; static QEMUTimer *active_timers[2]; #if defined(USE_WIN32_TIMER) || defined(USE_WIN32_DYNTICKS_TIMER) static MMRESULT timerID; static HANDLE host_alarm = NULL; static unsigned int period = 1; #endif QEMUClock *qemu_new_clock(int type) { QEMUClock *clock; clock = qemu_mallocz(sizeof(QEMUClock)); if (!clock) return NULL; clock->type = type; return clock; } QEMUTimer *qemu_new_timer(QEMUClock *clock, QEMUTimerCB *cb, void *opaque) { QEMUTimer *ts; ts = qemu_mallocz(sizeof(QEMUTimer)); ts->clock = clock; ts->cb = cb; ts->opaque = opaque; return ts; } void qemu_free_timer(QEMUTimer *ts) { qemu_free(ts); } /* stop a timer, but do not dealloc it */ void qemu_del_timer(QEMUTimer *ts) { QEMUTimer **pt, *t; /* NOTE: this code must be signal safe because qemu_timer_expired() can be called from a signal. */ pt = &active_timers[ts->clock->type]; for(;;) { t = *pt; if (!t) break; if (t == ts) { *pt = t->next; break; } pt = &t->next; } } /* modify the current timer so that it will be fired when current_time >= expire_time. The corresponding callback will be called. */ void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time) { QEMUTimer **pt, *t; qemu_del_timer(ts); /* 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]; for(;;) { t = *pt; if (!t) break; if (t->expire_time > expire_time) break; pt = &t->next; } ts->expire_time = expire_time; ts->next = *pt; *pt = ts; /* Rearm if necessary */ if ((alarm_timer->flags & ALARM_FLAG_EXPIRED) == 0 && pt == &active_timers[ts->clock->type]) alarm_timer_rearm(alarm_timer); } int qemu_timer_pending(QEMUTimer *ts) { QEMUTimer *t; for(t = active_timers[ts->clock->type]; t != NULL; t = t->next) { if (t == ts) return 1; } return 0; } static inline int qemu_timer_expired(QEMUTimer *timer_head, int64_t current_time) { if (!timer_head) return 0; return (timer_head->expire_time <= current_time); } #define QEMU_TIMER_MAX_TIMEOUT 10 static inline int qemu_timer_next_timeout(QEMUTimer* timer_head) { int64_t now, diff; if (!timer_head) return QEMU_TIMER_MAX_TIMEOUT; now = qemu_get_clock(timer_head->clock); diff = timer_head->expire_time - now; if (timer_head->clock == vm_clock) diff /= 1000000; if (diff > QEMU_TIMER_MAX_TIMEOUT) return QEMU_TIMER_MAX_TIMEOUT; if (diff < 1) diff = 1; return (int) diff; } static void qemu_run_timers(QEMUTimer **ptimer_head, int64_t current_time) { QEMUTimer *ts; for(;;) { ts = *ptimer_head; if (!ts || ts->expire_time > current_time) break; /* remove timer from the list before calling the callback */ *ptimer_head = ts->next; ts->next = NULL; /* run the callback (the timer list can be modified) */ ts->cb(ts->opaque); } } int64_t qemu_get_clock(QEMUClock *clock) { switch(clock->type) { case QEMU_TIMER_REALTIME: return get_clock() / 1000000; default: case QEMU_TIMER_VIRTUAL: return cpu_get_clock(); } } void init_timers(void) { static int inited; if (!inited) { init_get_clock(); ticks_per_sec = QEMU_TIMER_BASE; rt_clock = qemu_new_clock(QEMU_TIMER_REALTIME); vm_clock = qemu_new_clock(QEMU_TIMER_VIRTUAL); inited = 1; } } /* save a timer */ void qemu_put_timer(QEMUFile *f, QEMUTimer *ts) { uint64_t expire_time; if (qemu_timer_pending(ts)) { expire_time = ts->expire_time; } else { expire_time = -1; } qemu_put_be64(f, expire_time); } void qemu_get_timer(QEMUFile *f, QEMUTimer *ts) { uint64_t expire_time; expire_time = qemu_get_be64(f); if (expire_time != -1) { qemu_mod_timer(ts, expire_time); } else { qemu_del_timer(ts); } } void timer_save(QEMUFile *f, void *opaque) { if (cpu_ticks_enabled) { hw_error("cannot save state if virtual timers are running"); } qemu_put_be64s(f, (uint64_t*)&cpu_ticks_offset); qemu_put_be64s(f, (uint64_t*)&ticks_per_sec); } int timer_load(QEMUFile *f, void *opaque, int version_id) { if (version_id != 1) return -EINVAL; if (cpu_ticks_enabled) { return -EINVAL; } qemu_get_be64s(f, (uint64_t*)&cpu_ticks_offset); qemu_get_be64s(f, (uint64_t*)&ticks_per_sec); return 0; } #ifdef _WIN32 void CALLBACK host_alarm_handler(UINT uTimerID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2) #else static void host_alarm_handler(int host_signum) #endif { #if 0 //write( 2, "|", 1 ); #define DISP_FREQ 1000 { static int64_t delta_min = INT64_MAX; static int64_t delta_max, delta_cum, last_clock, delta, ti; static int count; ti = qemu_get_clock(vm_clock); if (last_clock != 0) { delta = ti - last_clock; if (delta < delta_min) delta_min = delta; if (delta > delta_max) delta_max = delta; delta_cum += delta; if (++count == DISP_FREQ) { printf("timer: min=%" PRId64 " us max=%" PRId64 " us avg=%" PRId64 " us avg_freq=%0.3f Hz\n", muldiv64(delta_min, 1000000, ticks_per_sec), muldiv64(delta_max, 1000000, ticks_per_sec), muldiv64(delta_cum, 1000000 / DISP_FREQ, ticks_per_sec), (double)ticks_per_sec / ((double)delta_cum / DISP_FREQ)); count = 0; delta_min = INT64_MAX; delta_max = 0; delta_cum = 0; } } last_clock = ti; } #endif if (alarm_timer_has_dynticks(alarm_timer) || qemu_timer_expired(active_timers[QEMU_TIMER_VIRTUAL], qemu_get_clock(vm_clock)) || qemu_timer_expired(active_timers[QEMU_TIMER_REALTIME], qemu_get_clock(rt_clock))) { #ifdef _WIN32 struct qemu_alarm_win32 *data = ((struct qemu_alarm_timer*)dwUser)->priv; SetEvent(data->host_alarm); #endif alarm_timer->flags |= ALARM_FLAG_EXPIRED; if (alarm_timer->signal) alarm_timer->signal(); } } static uint64_t qemu_next_deadline(void) { int64_t nearest_delta_us = INT64_MAX; int64_t vmdelta_us; if (active_timers[QEMU_TIMER_REALTIME]) nearest_delta_us = (active_timers[QEMU_TIMER_REALTIME]->expire_time - qemu_get_clock(rt_clock))*1000; if (active_timers[QEMU_TIMER_VIRTUAL]) { /* round up */ vmdelta_us = (active_timers[QEMU_TIMER_VIRTUAL]->expire_time - qemu_get_clock(vm_clock)+999)/1000; if (vmdelta_us < nearest_delta_us) nearest_delta_us = vmdelta_us; } /* Avoid arming the timer to negative, zero, or too low values */ if (nearest_delta_us <= MIN_TIMER_REARM_US) nearest_delta_us = MIN_TIMER_REARM_US; return nearest_delta_us; } #define RTC_FREQ 1024 #if defined(USE_HPET_TIMER) || defined(USE_RTC_TIMER) 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(fd, F_SETFL, O_ASYNC); fcntl(fd, F_SETOWN, getpid()); } #endif #ifdef USE_HPET_TIMER static int hpet_start_timer(struct qemu_alarm_timer *t) { struct hpet_info info; int r, fd; fd = 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->priv = (void *)(long)fd; return 0; fail: close(fd); return -1; } static void hpet_stop_timer(struct qemu_alarm_timer *t) { int fd = (long)t->priv; close(fd); } #endif #ifdef USE_RTC_TIMER static int rtc_start_timer(struct qemu_alarm_timer *t) { int rtc_fd; unsigned long current_rtc_freq = 0; TFR(rtc_fd = 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->priv = (void *)(long)rtc_fd; return 0; } static void rtc_stop_timer(struct qemu_alarm_timer *t) { int rtc_fd = (long)t->priv; close(rtc_fd); } #endif #ifdef USE_DYNTICKS_TIMER static int dynticks_start_timer(struct qemu_alarm_timer *t) { struct sigevent ev; timer_t host_timer; struct sigaction act; sigfillset(&act.sa_mask); act.sa_flags = 0; act.sa_handler = host_alarm_handler; sigaction(SIGALRM, &act, NULL); ev.sigev_value.sival_int = 0; ev.sigev_notify = SIGEV_SIGNAL; ev.sigev_signo = SIGALRM; if (timer_create(CLOCK_REALTIME, &ev, &host_timer)) { perror("timer_create"); /* disable dynticks */ fprintf(stderr, "Dynamic Ticks disabled\n"); return -1; } t->priv = (void *)host_timer; return 0; } static void dynticks_stop_timer(struct qemu_alarm_timer *t) { timer_t host_timer = (timer_t)t->priv; timer_delete(host_timer); } static void dynticks_rearm_timer(struct qemu_alarm_timer *t) { timer_t host_timer = (timer_t)t->priv; struct itimerspec timeout; int64_t nearest_delta_us = INT64_MAX; int64_t current_us; if (!active_timers[QEMU_TIMER_REALTIME] && !active_timers[QEMU_TIMER_VIRTUAL]) { return; } nearest_delta_us = qemu_next_deadline(); /* check whether a timer is already running */ if (timer_gettime(host_timer, &timeout)) { perror("gettime"); fprintf(stderr, "Internal timer error: aborting\n"); exit(1); } current_us = timeout.it_value.tv_sec * 1000000 + timeout.it_value.tv_nsec/1000; if (current_us && current_us <= nearest_delta_us) return; timeout.it_interval.tv_sec = 0; timeout.it_interval.tv_nsec = 0; /* 0 for one-shot timer */ timeout.it_value.tv_sec = nearest_delta_us / 1000000; timeout.it_value.tv_nsec = (nearest_delta_us % 1000000) * 1000; if (timer_settime(host_timer, 0 /* RELATIVE */, &timeout, NULL)) { perror("settime"); fprintf(stderr, "Internal timer error: aborting\n"); exit(1); } } #endif /* USE_DYNTICKS_TIMER */ #ifdef USE_UNIX_TIMER 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_flags = 0; act.sa_handler = host_alarm_handler; sigaction(SIGALRM, &act, NULL); 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; err = setitimer(ITIMER_REAL, &itv, NULL); if (err) return -1; return 0; } static void unix_stop_timer(struct qemu_alarm_timer *t) { struct itimerval itv; memset(&itv, 0, sizeof(itv)); setitimer(ITIMER_REAL, &itv, NULL); } #endif /* USE_UNIX_TIMER */ #if defined(USE_WIN32_TIMER) || defined(USE_WIN32_DYNTICKS_TIMER) static int win32_start_timer(struct qemu_alarm_timer *t) { TIMECAPS tc; struct qemu_alarm_win32 *data = t->priv; UINT flags; data->host_alarm = CreateEvent(NULL, FALSE, FALSE, NULL); if (!data->host_alarm) { perror("Failed CreateEvent"); return -1; } memset(&tc, 0, sizeof(tc)); timeGetDevCaps(&tc, sizeof(tc)); if (data->period < tc.wPeriodMin) data->period = tc.wPeriodMin; timeBeginPeriod(data->period); flags = TIME_CALLBACK_FUNCTION; if (alarm_timer_has_dynticks(t)) flags |= TIME_ONESHOT; else flags |= TIME_PERIODIC; data->timerId = timeSetEvent(1, // interval (ms) data->period, // resolution host_alarm_handler, // function (DWORD)t, // parameter flags); if (!data->timerId) { perror("Failed to initialize win32 alarm timer"); timeEndPeriod(data->period); CloseHandle(data->host_alarm); return -1; } qemu_add_wait_object(data->host_alarm, NULL, NULL); return 0; } static void win32_stop_timer(struct qemu_alarm_timer *t) { struct qemu_alarm_win32 *data = t->priv; timeKillEvent(data->timerId); timeEndPeriod(data->period); CloseHandle(data->host_alarm); } #endif /* USE_WIN32_TIMER || USE_WIN32_DYNTICKS_TIMER */ #ifdef USE_WIN32_DYNTICKS_TIMER static void win32_rearm_timer(struct qemu_alarm_timer *t) { struct qemu_alarm_win32 *data = t->priv; uint64_t nearest_delta_us; if (!active_timers[QEMU_TIMER_REALTIME] && !active_timers[QEMU_TIMER_VIRTUAL]) return; nearest_delta_us = qemu_next_deadline(); nearest_delta_us /= 1000; timeKillEvent(data->timerId); data->timerId = timeSetEvent(1, data->period, host_alarm_handler, (DWORD)t, TIME_ONESHOT | TIME_PERIODIC); if (!data->timerId) { perror("Failed to re-arm win32 alarm timer"); timeEndPeriod(data->period); CloseHandle(data->host_alarm); exit(1); } } #endif /* USE_WIN32_DYNTICKS_TIMER */ void qemu_init_alarm_timer(void (*cb)(void)) { struct qemu_alarm_timer *t; int i, err = -1; /* on UNIX, ensure that SIGALRM is not blocked for some reason */ #ifndef _WIN32 { sigset_t ss; sigemptyset( &ss ); sigaddset( &ss, SIGALRM ); sigprocmask( SIG_UNBLOCK, &ss, NULL ); } #endif for (i = 0; alarm_timers[i].name; i++) { t = &alarm_timers[i]; err = t->start(t); if (!err) break; } if (err) { fprintf(stderr, "Unable to find any suitable alarm timer.\n"); fprintf(stderr, "Terminating\n"); exit(1); } t->signal = cb; D( "using '%s' alarm timer", t->name ); alarm_timer = t; } #if 0 static void quit_timers(void) { alarm_timer->stop(alarm_timer); alarm_timer = NULL; } #endif void qemu_run_virtual_timers(void) { qemu_run_timers(&active_timers[QEMU_TIMER_VIRTUAL], qemu_get_clock(vm_clock)); } void qemu_run_realtime_timers(void) { qemu_run_timers(&active_timers[QEMU_TIMER_REALTIME], qemu_get_clock(rt_clock)); } void qemu_start_alarm_timer(void) { alarm_timer_rearm(alarm_timer); } void qemu_rearm_alarm_timer(void) { if (alarm_timer->flags & ALARM_FLAG_EXPIRED) { alarm_timer->flags &= ~(ALARM_FLAG_EXPIRED); alarm_timer_rearm(alarm_timer); } } void qemu_stop_alarm_timer(void) { alarm_timer->stop(alarm_timer); }