static void mm_rearm_timer(struct qemu_alarm_timer *t) { int nearest_delta_ms; assert(alarm_has_dynticks(t)); if (!qemu_clock_has_timers(QEMU_CLOCK_REALTIME) && !qemu_clock_has_timers(QEMU_CLOCK_VIRTUAL) && !qemu_clock_has_timers(QEMU_CLOCK_HOST)) { 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 void win32_rearm_timer(struct qemu_alarm_timer *t) { HANDLE hTimer = t->timer; int nearest_delta_ms; BOOLEAN success; assert(alarm_has_dynticks(t)); if (!qemu_clock_has_timers(QEMU_CLOCK_REALTIME) && !qemu_clock_has_timers(QEMU_CLOCK_VIRTUAL) && !qemu_clock_has_timers(QEMU_CLOCK_HOST)) { return; } nearest_delta_ms = (qemu_next_alarm_deadline() + 999999) / 1000000; if (nearest_delta_ms < 1) { nearest_delta_ms = 1; } success = ChangeTimerQueueTimer(NULL, hTimer, nearest_delta_ms, 3600000); if (!success) { fprintf(stderr, "Failed to rearm win32 alarm timer: %ld\n", GetLastError()); exit(-1); } }
void qemu_clock_warp(QEMUClock *clock) { int64_t deadline; /* * There are too many global variables to make the "warp" behavior * applicable to other clocks. But a clock argument removes the * need for if statements all over the place. */ if (clock != vm_clock || !use_icount) { return; } /* * If the CPUs have been sleeping, advance the vm_clock timer now. This * ensures that the deadline for the timer is computed correctly below. * This also makes sure that the insn counter is synchronized before the * CPU starts running, in case the CPU is woken by an event other than * the earliest vm_clock timer. */ icount_warp_rt(NULL); if (!all_cpu_threads_idle() || !qemu_clock_has_timers(vm_clock)) { qemu_del_timer(icount_warp_timer); return; } if (qtest_enabled()) { /* When testing, qtest commands advance icount. */ return; } vm_clock_warp_start = qemu_get_clock_ns(rt_clock); deadline = qemu_clock_deadline(vm_clock); if (deadline > 0) { /* * Ensure the vm_clock proceeds even when the virtual CPU goes to * sleep. Otherwise, the CPU might be waiting for a future timer * interrupt to wake it up, but the interrupt never comes because * the vCPU isn't running any insns and thus doesn't advance the * vm_clock. * * An extreme solution for this problem would be to never let VCPUs * sleep in icount mode if there is a pending vm_clock timer; rather * time could just advance to the next vm_clock event. Instead, we * do stop VCPUs and only advance vm_clock after some "real" time, * (related to the time left until the next event) has passed. This * rt_clock timer will do this. This avoids that the warps are too * visible externally---for example, you will not be sending network * packets continuously instead of every 100ms. */ qemu_mod_timer(icount_warp_timer, vm_clock_warp_start + deadline); } else { LOGD_CPUS("%s=>qemu_notify_event()\n", __func__); qemu_notify_event(); } }
static void dynticks_rearm_timer(struct qemu_alarm_timer *t) { timer_t host_timer = t->timer; struct itimerspec timeout; int64_t nearest_delta_ns = INT64_MAX; int64_t current_ns; assert(alarm_has_dynticks(t)); if (!qemu_clock_has_timers(QEMU_CLOCK_REALTIME) && !qemu_clock_has_timers(QEMU_CLOCK_VIRTUAL) && !qemu_clock_has_timers(QEMU_CLOCK_HOST)) return; nearest_delta_ns = qemu_next_alarm_deadline(); 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); } }
void qemu_clock_warp(QEMUClockType type) { int64_t deadline; /* * There are too many global variables to make the "warp" behavior * applicable to other clocks. But a clock argument removes the * need for if statements all over the place. */ if (type != QEMU_CLOCK_VIRTUAL || !use_icount) { return; } /* * If the CPUs have been sleeping, advance QEMU_CLOCK_VIRTUAL timer now. * This ensures that the deadline for the timer is computed correctly below. * This also makes sure that the insn counter is synchronized before the * CPU starts running, in case the CPU is woken by an event other than * the earliest QEMU_CLOCK_VIRTUAL timer. */ icount_warp_rt(NULL); if (!all_cpu_threads_idle() || !qemu_clock_has_timers(QEMU_CLOCK_VIRTUAL)) { timer_del(icount_warp_timer); return; } if (qtest_enabled()) { /* When testing, qtest commands advance icount. */ return; } vm_clock_warp_start = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); /* We want to use the earliest deadline from ALL vm_clocks */ deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL); /* Maintain prior (possibly buggy) behaviour where if no deadline * was set (as there is no QEMU_CLOCK_VIRTUAL timer) or it is more than * INT32_MAX nanoseconds ahead, we still use INT32_MAX * nanoseconds. */ if ((deadline < 0) || (deadline > INT32_MAX)) { deadline = INT32_MAX; } if (deadline > 0) { /* * Ensure QEMU_CLOCK_VIRTUAL proceeds even when the virtual CPU goes to * sleep. Otherwise, the CPU might be waiting for a future timer * interrupt to wake it up, but the interrupt never comes because * the vCPU isn't running any insns and thus doesn't advance the * QEMU_CLOCK_VIRTUAL. * * An extreme solution for this problem would be to never let VCPUs * sleep in icount mode if there is a pending QEMU_CLOCK_VIRTUAL * timer; rather time could just advance to the next QEMU_CLOCK_VIRTUAL * event. Instead, we do stop VCPUs and only advance QEMU_CLOCK_VIRTUAL * after some e"real" time, (related to the time left until the next * event) has passed. The QEMU_CLOCK_REALTIME timer will do this. * This avoids that the warps are visible externally; for example, * you will not be sending network packets continuously instead of * every 100ms. */ timer_mod(icount_warp_timer, vm_clock_warp_start + deadline); } else if (deadline == 0) { qemu_clock_notify(QEMU_CLOCK_VIRTUAL); } }