diff options
Diffstat (limited to 'qemu-timer.c')
-rw-r--r-- | qemu-timer.c | 500 |
1 files changed, 1 insertions, 499 deletions
diff --git a/qemu-timer.c b/qemu-timer.c index b56bfde706..8ea8211873 100644 --- a/qemu-timer.c +++ b/qemu-timer.c @@ -33,10 +33,6 @@ #include <pthread.h> #endif -#ifdef _WIN32 -#include <mmsystem.h> -#endif - #ifdef CONFIG_PPOLL #include <poll.h> #endif @@ -77,174 +73,11 @@ struct QEMUTimerList { void *notify_opaque; }; -struct qemu_alarm_timer { - char const *name; - int (*start)(struct qemu_alarm_timer *t); - void (*stop)(struct qemu_alarm_timer *t); - void (*rearm)(struct qemu_alarm_timer *t, int64_t nearest_delta_ns); -#if defined(__linux__) - timer_t timer; - int fd; -#elif defined(_WIN32) - HANDLE timer; -#endif - bool expired; - bool pending; -}; - -static struct qemu_alarm_timer *alarm_timer; - static bool timer_expired_ns(QEMUTimer *timer_head, int64_t current_time) { return timer_head && (timer_head->expire_time <= current_time); } -static int64_t qemu_next_alarm_deadline(void) -{ - int64_t delta = INT64_MAX; - int64_t rtdelta; - int64_t hdelta; - - if (!use_icount && vm_clock->enabled && - vm_clock->main_loop_timerlist->active_timers) { - delta = vm_clock->main_loop_timerlist->active_timers->expire_time - - qemu_get_clock_ns(vm_clock); - } - if (host_clock->enabled && - host_clock->main_loop_timerlist->active_timers) { - hdelta = host_clock->main_loop_timerlist->active_timers->expire_time - - qemu_get_clock_ns(host_clock); - if (hdelta < delta) { - delta = hdelta; - } - } - if (rt_clock->enabled && - rt_clock->main_loop_timerlist->active_timers) { - rtdelta = (rt_clock->main_loop_timerlist->active_timers->expire_time - - qemu_get_clock_ns(rt_clock)); - if (rtdelta < delta) { - delta = rtdelta; - } - } - - return delta; -} - -static void qemu_rearm_alarm_timer(struct qemu_alarm_timer *t) -{ - int64_t nearest_delta_ns = qemu_next_alarm_deadline(); - if (nearest_delta_ns < INT64_MAX) { - t->rearm(t, nearest_delta_ns); - } -} - -/* TODO: MIN_TIMER_REARM_NS should be optimized */ -#define MIN_TIMER_REARM_NS 250000 - -#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, int64_t delta); - -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, int64_t delta); - -#else - -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, int64_t delta); - -#ifdef __linux__ - -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, int64_t delta); - -#endif /* __linux__ */ - -#endif /* _WIN32 */ - -static struct qemu_alarm_timer alarm_timers[] = { -#ifndef _WIN32 -#ifdef __linux__ - {"dynticks", dynticks_start_timer, - dynticks_stop_timer, dynticks_rearm_timer}, -#endif - {"unix", unix_start_timer, unix_stop_timer, unix_rearm_timer}, -#else - {"mmtimer", mm_start_timer, mm_stop_timer, mm_rearm_timer}, - {"dynticks", win32_start_timer, win32_stop_timer, win32_rearm_timer}, -#endif - {NULL, } -}; - -static void show_available_alarms(void) -{ - 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 configure_alarms(char const *opt) -{ - int i; - int cur = 0; - int count = ARRAY_SIZE(alarm_timers) - 1; - char *arg; - char *name; - struct qemu_alarm_timer tmp; - - if (is_help_option(opt)) { - show_available_alarms(); - exit(0); - } - - arg = g_strdup(opt); - - /* Reorder the array */ - name = strtok(arg, ","); - while (name) { - 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, ","); - } - - g_free(arg); - - if (cur) { - /* Disable remaining timers */ - for (i = cur; i < count; i++) - alarm_timers[i].name = NULL; - } else { - show_available_alarms(); - exit(1); - } -} - static QEMUTimerList *timerlist_new_from_clock(QEMUClock *clock, QEMUTimerListNotifyCB *cb, void *opaque) @@ -318,7 +151,6 @@ void qemu_clock_enable(QEMUClock *clock, bool enabled) clock->enabled = enabled; if (enabled && !old) { qemu_clock_notify(clock); - qemu_rearm_alarm_timer(alarm_timer); } } @@ -542,9 +374,6 @@ void qemu_mod_timer_ns(QEMUTimer *ts, int64_t expire_time) /* Rearm if necessary */ if (pt == &ts->timer_list->active_timers) { - if (!alarm_timer->pending) { - qemu_rearm_alarm_timer(alarm_timer); - } /* Interrupt execution to force deadline recalculation. */ qemu_clock_warp(ts->timer_list->clock); timerlist_notify(ts->timer_list); @@ -703,338 +532,11 @@ uint64_t timer_expire_time_ns(QEMUTimer *ts) bool qemu_run_all_timers(void) { bool progress = false; - alarm_timer->pending = false; - - /* vm time timers */ QEMUClockType type; + for (type = 0; type < QEMU_CLOCK_MAX; type++) { progress |= qemu_run_timers(qemu_clock_ptr(type)); } - /* rearm timer, if not periodic */ - if (alarm_timer->expired) { - alarm_timer->expired = false; - qemu_rearm_alarm_timer(alarm_timer); - } - return progress; } - -#ifdef _WIN32 -static void CALLBACK host_alarm_handler(PVOID lpParam, BOOLEAN unused) -#else -static void host_alarm_handler(int host_signum) -#endif -{ - struct qemu_alarm_timer *t = alarm_timer; - if (!t) - return; - - t->expired = true; - t->pending = true; - qemu_notify_event(); -} - -#if defined(__linux__) - -#include "qemu/compatfd.h" - -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); - - /* - * Initialize ev struct to 0 to avoid valgrind complaining - * about uninitialized data in timer_create call - */ - memset(&ev, 0, sizeof(ev)); - ev.sigev_value.sival_int = 0; - ev.sigev_notify = SIGEV_SIGNAL; -#ifdef CONFIG_SIGEV_THREAD_ID - if (qemu_signalfd_available()) { - ev.sigev_notify = SIGEV_THREAD_ID; - ev._sigev_un._tid = qemu_get_thread_id(); - } -#endif /* CONFIG_SIGEV_THREAD_ID */ - ev.sigev_signo = SIGALRM; - - if (timer_create(CLOCK_REALTIME, &ev, &host_timer)) { - perror("timer_create"); - return -1; - } - - t->timer = host_timer; - - return 0; -} - -static void dynticks_stop_timer(struct qemu_alarm_timer *t) -{ - timer_t host_timer = t->timer; - - timer_delete(host_timer); -} - -static void dynticks_rearm_timer(struct qemu_alarm_timer *t, - int64_t nearest_delta_ns) -{ - timer_t host_timer = t->timer; - struct itimerspec timeout; - int64_t current_ns; - - if (nearest_delta_ns < MIN_TIMER_REARM_NS) - nearest_delta_ns = MIN_TIMER_REARM_NS; - - /* 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_ns = timeout.it_value.tv_sec * 1000000000LL + timeout.it_value.tv_nsec; - if (current_ns && current_ns <= nearest_delta_ns) - 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_ns / 1000000000; - timeout.it_value.tv_nsec = nearest_delta_ns % 1000000000; - if (timer_settime(host_timer, 0 /* RELATIVE */, &timeout, NULL)) { - perror("settime"); - fprintf(stderr, "Internal timer error: aborting\n"); - exit(1); - } -} - -#endif /* defined(__linux__) */ - -#if !defined(_WIN32) - -static int unix_start_timer(struct qemu_alarm_timer *t) -{ - struct sigaction act; - - /* timer signal */ - sigfillset(&act.sa_mask); - act.sa_flags = 0; - act.sa_handler = host_alarm_handler; - - sigaction(SIGALRM, &act, NULL); - return 0; -} - -static void unix_rearm_timer(struct qemu_alarm_timer *t, - int64_t nearest_delta_ns) -{ - struct itimerval itv; - int err; - - 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) -{ - struct itimerval itv; - - memset(&itv, 0, sizeof(itv)); - setitimer(ITIMER_REAL, &itv, NULL); -} - -#endif /* !defined(_WIN32) */ - - -#ifdef _WIN32 - -static MMRESULT mm_timer; -static TIMECAPS mm_tc; - -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; - } - t->expired = true; - t->pending = true; - qemu_notify_event(); -} - -static int mm_start_timer(struct qemu_alarm_timer *t) -{ - timeGetDevCaps(&mm_tc, sizeof(mm_tc)); - return 0; -} - -static void mm_stop_timer(struct qemu_alarm_timer *t) -{ - if (mm_timer) { - timeKillEvent(mm_timer); - } -} - -static void mm_rearm_timer(struct qemu_alarm_timer *t, int64_t delta) -{ - int64_t nearest_delta_ms = delta / 1000000; - if (nearest_delta_ms < mm_tc.wPeriodMin) { - nearest_delta_ms = mm_tc.wPeriodMin; - } else if (nearest_delta_ms > mm_tc.wPeriodMax) { - nearest_delta_ms = mm_tc.wPeriodMax; - } - - if (mm_timer) { - timeKillEvent(mm_timer); - } - mm_timer = timeSetEvent((UINT)nearest_delta_ms, - mm_tc.wPeriodMin, - mm_alarm_handler, - (DWORD_PTR)t, - TIME_ONESHOT | TIME_CALLBACK_FUNCTION); - - if (!mm_timer) { - fprintf(stderr, "Failed to re-arm win32 alarm timer\n"); - timeEndPeriod(mm_tc.wPeriodMin); - exit(1); - } -} - -static int win32_start_timer(struct qemu_alarm_timer *t) -{ - HANDLE hTimer; - BOOLEAN success; - - /* If you call ChangeTimerQueueTimer on a one-shot timer (its period - is zero) that has already expired, the timer is not updated. Since - creating a new timer is relatively expensive, set a bogus one-hour - interval in the dynticks case. */ - success = CreateTimerQueueTimer(&hTimer, - NULL, - host_alarm_handler, - t, - 1, - 3600000, - WT_EXECUTEINTIMERTHREAD); - - if (!success) { - fprintf(stderr, "Failed to initialize win32 alarm timer: %ld\n", - GetLastError()); - return -1; - } - - t->timer = hTimer; - return 0; -} - -static void win32_stop_timer(struct qemu_alarm_timer *t) -{ - HANDLE hTimer = t->timer; - - if (hTimer) { - DeleteTimerQueueTimer(NULL, hTimer, NULL); - } -} - -static void win32_rearm_timer(struct qemu_alarm_timer *t, - int64_t nearest_delta_ns) -{ - HANDLE hTimer = t->timer; - int64_t nearest_delta_ms; - BOOLEAN success; - - nearest_delta_ms = nearest_delta_ns / 1000000; - if (nearest_delta_ms < 1) { - nearest_delta_ms = 1; - } - /* ULONG_MAX can be 32 bit */ - if (nearest_delta_ms > ULONG_MAX) { - nearest_delta_ms = ULONG_MAX; - } - success = ChangeTimerQueueTimer(NULL, - hTimer, - (unsigned long) nearest_delta_ms, - 3600000); - - if (!success) { - fprintf(stderr, "Failed to rearm win32 alarm timer: %ld\n", - GetLastError()); - exit(-1); - } - -} - -#endif /* _WIN32 */ - -static void quit_timers(void) -{ - struct qemu_alarm_timer *t = alarm_timer; - alarm_timer = NULL; - t->stop(t); -} - -#ifdef CONFIG_POSIX -static void reinit_timers(void) -{ - struct qemu_alarm_timer *t = alarm_timer; - t->stop(t); - if (t->start(t)) { - fprintf(stderr, "Internal timer error: aborting\n"); - exit(1); - } - qemu_rearm_alarm_timer(t); -} -#endif /* CONFIG_POSIX */ - -int init_timer_alarm(void) -{ - struct qemu_alarm_timer *t = NULL; - int i, err = -1; - - if (alarm_timer) { - return 0; - } - - for (i = 0; alarm_timers[i].name; i++) { - t = &alarm_timers[i]; - - err = t->start(t); - if (!err) - break; - } - - if (err) { - err = -ENOENT; - goto fail; - } - - atexit(quit_timers); -#ifdef CONFIG_POSIX - pthread_atfork(NULL, NULL, reinit_timers); -#endif - alarm_timer = t; - return 0; - -fail: - return err; -} - |