From a7fb77d6eca56e61e94f62e7deb4120b60b1e919 Mon Sep 17 00:00:00 2001 From: David 'Digit' Turner Date: Mon, 10 May 2010 23:50:54 -0700 Subject: Upstream: integrate timer/clock management changes. Change-Id: I24acbdebe58d207352548f54dda1abf5be01e7d4 --- vl.c | 284 +++++++++++++++++++++++++++++++++++++++---------------------------- 1 file changed, 165 insertions(+), 119 deletions(-) (limited to 'vl.c') diff --git a/vl.c b/vl.c index aa118ff..9915f1e 100644 --- a/vl.c +++ b/vl.c @@ -205,7 +205,6 @@ enum vga_retrace_method vga_retrace_method = VGA_RETRACE_DUMB; static DisplayState *display_state; DisplayType display_type = DT_DEFAULT; const char* keyboard_layout = NULL; -int64_t ticks_per_sec; ram_addr_t ram_size; int nb_nics; NICInfo nd_table[MAX_NICS]; @@ -217,6 +216,7 @@ int cirrus_vga_enabled = 1; int std_vga_enabled = 0; int vmsvga_enabled = 0; int xenfb_enabled = 0; +QEMUClock *rtc_clock; #ifdef TARGET_SPARC int graphic_width = 1024; int graphic_height = 768; @@ -528,6 +528,20 @@ void hw_error(const char *fmt, ...) abort(); } +static void set_proc_name(const char *s) +{ +#if defined(__linux__) && defined(PR_SET_NAME) + char name[16]; + if (!s) + return; + name[sizeof(name) - 1] = 0; + strncpy(name, s, sizeof(name)); + /* Could rewrite argv[0] too, but that's a bit more complicated. + This simple way is enough for `top'. */ + prctl(PR_SET_NAME, name); +#endif +} + /***************/ /* ballooning */ @@ -716,6 +730,9 @@ void do_mouse_set(Monitor *mon, int index) monitor_printf(mon, "Mouse at given index not found\n"); } +/***********************************************************/ +/* real time host monotonic timer */ + /* compute with 96 bit intermediate result: (a*b)/c */ uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c) { @@ -740,10 +757,13 @@ uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c) return res.ll; } -/***********************************************************/ -/* real time host monotonic timer */ +static int64_t get_clock_realtime(void) +{ + struct timeval tv; -#define QEMU_TIMER_BASE 1000000000LL + gettimeofday(&tv, NULL); + return tv.tv_sec * 1000000000LL + (tv.tv_usec * 1000); +} #ifdef WIN32 @@ -765,7 +785,7 @@ static int64_t get_clock(void) { LARGE_INTEGER ti; QueryPerformanceCounter(&ti); - return muldiv64(ti.QuadPart, QEMU_TIMER_BASE, clock_freq); + return muldiv64(ti.QuadPart, get_ticks_per_sec(), clock_freq); } #else @@ -776,7 +796,7 @@ static void init_get_clock(void) { use_rt_clock = 0; #if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD_version >= 500000) \ - || defined(__DragonFly__) + || defined(__DragonFly__) || defined(__FreeBSD_kernel__) { struct timespec ts; if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) { @@ -789,7 +809,7 @@ static void init_get_clock(void) static int64_t get_clock(void) { #if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD_version >= 500000) \ - || defined(__DragonFly__) + || defined(__DragonFly__) || defined(__FreeBSD_kernel__) if (use_rt_clock) { struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); @@ -799,9 +819,7 @@ static int64_t get_clock(void) { /* 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); + return get_clock_realtime(); } } #endif @@ -823,10 +841,15 @@ static int64_t cpu_get_icount(void) /***********************************************************/ /* 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; +typedef struct TimersState { + int64_t cpu_ticks_prev; + int64_t cpu_ticks_offset; + int64_t cpu_clock_offset; + int32_t cpu_ticks_enabled; + int64_t dummy; +} TimersState; + +TimersState timers_state; /* return the host CPU cycle counter and handle stop/restart */ int64_t cpu_get_ticks(void) @@ -834,18 +857,18 @@ int64_t cpu_get_ticks(void) if (use_icount) { return cpu_get_icount(); } - if (!cpu_ticks_enabled) { - return cpu_ticks_offset; + if (!timers_state.cpu_ticks_enabled) { + return timers_state.cpu_ticks_offset; } else { int64_t ticks; ticks = cpu_get_real_ticks(); - if (cpu_ticks_prev > ticks) { + if (timers_state.cpu_ticks_prev > ticks) { /* Note: non increasing ticks may happen if the host uses software suspend */ - cpu_ticks_offset += cpu_ticks_prev - ticks; + timers_state.cpu_ticks_offset += timers_state.cpu_ticks_prev - ticks; } - cpu_ticks_prev = ticks; - return ticks + cpu_ticks_offset; + timers_state.cpu_ticks_prev = ticks; + return ticks + timers_state.cpu_ticks_offset; } } @@ -853,21 +876,21 @@ int64_t cpu_get_ticks(void) static int64_t cpu_get_clock(void) { int64_t ti; - if (!cpu_ticks_enabled) { - return cpu_clock_offset; + if (!timers_state.cpu_ticks_enabled) { + return timers_state.cpu_clock_offset; } else { ti = get_clock(); - return ti + cpu_clock_offset; + return ti + timers_state.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; + if (!timers_state.cpu_ticks_enabled) { + timers_state.cpu_ticks_offset -= cpu_get_real_ticks(); + timers_state.cpu_clock_offset -= get_clock(); + timers_state.cpu_ticks_enabled = 1; } } @@ -875,18 +898,19 @@ void cpu_enable_ticks(void) 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; + if (timers_state.cpu_ticks_enabled) { + timers_state.cpu_ticks_offset = cpu_get_ticks(); + timers_state.cpu_clock_offset = cpu_get_clock(); + timers_state.cpu_ticks_enabled = 0; } } /***********************************************************/ /* timers */ -#define QEMU_TIMER_REALTIME 0 -#define QEMU_TIMER_VIRTUAL 1 +#define QEMU_CLOCK_REALTIME 0 +#define QEMU_CLOCK_VIRTUAL 1 +#define QEMU_CLOCK_HOST 2 struct QEMUClock { int type; @@ -968,7 +992,7 @@ static void rtc_stop_timer(struct qemu_alarm_timer *t); fairly approximate, so ignore small variation. When the guest is idle real and virtual time will be aligned in the IO wait loop. */ -#define ICOUNT_WOBBLE (QEMU_TIMER_BASE / 10) +#define ICOUNT_WOBBLE (get_ticks_per_sec() / 10) static void icount_adjust(void) { @@ -1010,7 +1034,7 @@ static void icount_adjust_rt(void * opaque) static void icount_adjust_vm(void * opaque) { qemu_mod_timer(icount_vm_timer, - qemu_get_clock(vm_clock) + QEMU_TIMER_BASE / 10); + qemu_get_clock(vm_clock) + get_ticks_per_sec() / 10); icount_adjust(); } @@ -1026,7 +1050,7 @@ static void init_icount_adjust(void) qemu_get_clock(rt_clock) + 1000); icount_vm_timer = qemu_new_timer(vm_clock, icount_adjust_vm, NULL); qemu_mod_timer(icount_vm_timer, - qemu_get_clock(vm_clock) + QEMU_TIMER_BASE / 10); + qemu_get_clock(vm_clock) + get_ticks_per_sec() / 10); } static struct qemu_alarm_timer alarm_timers[] = { @@ -1072,7 +1096,7 @@ static void configure_alarms(char const *opt) exit(0); } - arg = strdup(opt); + arg = qemu_strdup(opt); /* Reorder the array */ name = strtok(arg, ","); @@ -1101,7 +1125,7 @@ next: name = strtok(NULL, ","); } - free(arg); + qemu_free(arg); if (cur) { /* Disable remaining timers */ @@ -1113,10 +1137,13 @@ next: } } +#define QEMU_NUM_CLOCKS 3 + QEMUClock *rt_clock; QEMUClock *vm_clock; +QEMUClock *host_clock; -static QEMUTimer *active_timers[2]; +static QEMUTimer *active_timers[QEMU_NUM_CLOCKS]; static QEMUClock *qemu_new_clock(int type) { @@ -1207,7 +1234,7 @@ int qemu_timer_pending(QEMUTimer *ts) return 0; } -static inline int qemu_timer_expired(QEMUTimer *timer_head, int64_t current_time) +int qemu_timer_expired(QEMUTimer *timer_head, int64_t current_time) { if (!timer_head) return 0; @@ -1234,24 +1261,45 @@ static void qemu_run_timers(QEMUTimer **ptimer_head, int64_t current_time) int64_t qemu_get_clock(QEMUClock *clock) { switch(clock->type) { - case QEMU_TIMER_REALTIME: + case QEMU_CLOCK_REALTIME: return get_clock() / 1000000; default: - case QEMU_TIMER_VIRTUAL: + case QEMU_CLOCK_VIRTUAL: + if (use_icount) { + return cpu_get_icount(); + } else { + return cpu_get_clock(); + } + case QEMU_CLOCK_HOST: + return get_clock_realtime(); + } +} + +int64_t qemu_get_clock_ns(QEMUClock *clock) +{ + switch(clock->type) { + case QEMU_CLOCK_REALTIME: + return get_clock(); + default: + case QEMU_CLOCK_VIRTUAL: if (use_icount) { return cpu_get_icount(); } else { return cpu_get_clock(); } + case QEMU_CLOCK_HOST: + return get_clock_realtime(); } } -static void init_timers(void) +static void init_clocks(void) { 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); + rt_clock = qemu_new_clock(QEMU_CLOCK_REALTIME); + vm_clock = qemu_new_clock(QEMU_CLOCK_VIRTUAL); + host_clock = qemu_new_clock(QEMU_CLOCK_HOST); + + rtc_clock = host_clock; } /* save a timer */ @@ -1279,30 +1327,18 @@ void qemu_get_timer(QEMUFile *f, QEMUTimer *ts) } } -static void timer_save(QEMUFile *f, void *opaque) -{ - if (cpu_ticks_enabled) { - hw_error("cannot save state if virtual timers are running"); +static const VMStateDescription vmstate_timers = { + .name = "timer", + .version_id = 2, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_INT64(cpu_ticks_offset, TimersState), + VMSTATE_INT64(dummy, TimersState), + VMSTATE_INT64_V(cpu_clock_offset, TimersState, 2), + VMSTATE_END_OF_LIST() } - qemu_put_be64(f, cpu_ticks_offset); - qemu_put_be64(f, ticks_per_sec); - qemu_put_be64(f, cpu_clock_offset); -} - -static int timer_load(QEMUFile *f, void *opaque, int version_id) -{ - if (version_id != 1 && version_id != 2) - return -EINVAL; - if (cpu_ticks_enabled) { - return -EINVAL; - } - cpu_ticks_offset=qemu_get_be64(f); - ticks_per_sec=qemu_get_be64(f); - if (version_id == 2) { - cpu_clock_offset=qemu_get_be64(f); - } - return 0; -} +}; static void qemu_event_increment(void); @@ -1330,10 +1366,10 @@ static void host_alarm_handler(int host_signum) 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)); + muldiv64(delta_min, 1000000, get_ticks_per_sec()), + muldiv64(delta_max, 1000000, get_ticks_per_sec()), + muldiv64(delta_cum, 1000000 / DISP_FREQ, get_ticks_per_sec()), + (double)get_ticks_per_sec() / ((double)delta_cum / DISP_FREQ)); count = 0; delta_min = INT64_MAX; delta_max = 0; @@ -1345,10 +1381,12 @@ static void host_alarm_handler(int host_signum) #endif if (alarm_has_dynticks(alarm_timer) || (!use_icount && - qemu_timer_expired(active_timers[QEMU_TIMER_VIRTUAL], + qemu_timer_expired(active_timers[QEMU_CLOCK_VIRTUAL], qemu_get_clock(vm_clock))) || - qemu_timer_expired(active_timers[QEMU_TIMER_REALTIME], - qemu_get_clock(rt_clock))) { + qemu_timer_expired(active_timers[QEMU_CLOCK_REALTIME], + qemu_get_clock(rt_clock)) || + qemu_timer_expired(active_timers[QEMU_CLOCK_HOST], + qemu_get_clock(host_clock))) { qemu_event_increment(); if (alarm_timer) alarm_timer->flags |= ALARM_FLAG_EXPIRED; @@ -1356,11 +1394,6 @@ static void host_alarm_handler(int host_signum) if (next_cpu) { /* stop the currently executing cpu because a timer occured */ cpu_exit(next_cpu); -#ifdef CONFIG_KQEMU - if (next_cpu->kqemu_enabled) { - kqemu_cpu_interrupt(next_cpu); - } -#endif } #endif timer_alarm_pending = 1; @@ -1370,14 +1403,18 @@ static void host_alarm_handler(int host_signum) static int64_t qemu_next_deadline(void) { - int64_t delta; + /* To avoid problems with overflow limit this to 2^32. */ + int64_t delta = INT32_MAX; - if (active_timers[QEMU_TIMER_VIRTUAL]) { - delta = active_timers[QEMU_TIMER_VIRTUAL]->expire_time - + if (active_timers[QEMU_CLOCK_VIRTUAL]) { + delta = active_timers[QEMU_CLOCK_VIRTUAL]->expire_time - qemu_get_clock(vm_clock); - } else { - /* To avoid problems with overflow limit this to 2^32. */ - delta = INT32_MAX; + } + if (active_timers[QEMU_CLOCK_HOST]) { + int64_t hdelta = active_timers[QEMU_CLOCK_HOST]->expire_time - + qemu_get_clock(host_clock); + if (hdelta < delta) + delta = hdelta; } if (delta < 0) @@ -1386,7 +1423,7 @@ static int64_t qemu_next_deadline(void) return delta; } -#if defined(__linux__) || defined(_WIN32) +#if defined(__linux__) static uint64_t qemu_next_deadline_dyntick(void) { int64_t delta; @@ -1397,8 +1434,8 @@ static uint64_t qemu_next_deadline_dyntick(void) else delta = (qemu_next_deadline() + 999) / 1000; - if (active_timers[QEMU_TIMER_REALTIME]) { - rtdelta = (active_timers[QEMU_TIMER_REALTIME]->expire_time - + if (active_timers[QEMU_CLOCK_REALTIME]) { + rtdelta = (active_timers[QEMU_CLOCK_REALTIME]->expire_time - qemu_get_clock(rt_clock))*1000; if (rtdelta < delta) delta = rtdelta; @@ -1451,7 +1488,7 @@ static int hpet_start_timer(struct qemu_alarm_timer *t) struct hpet_info info; int r, fd; - fd = open("/dev/hpet", O_RDONLY); + fd = qemu_open("/dev/hpet", O_RDONLY); if (fd < 0) return -1; @@ -1500,7 +1537,7 @@ 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)); + TFR(rtc_fd = qemu_open("/dev/rtc", O_RDONLY)); if (rtc_fd < 0) return -1; ioctl(rtc_fd, RTC_IRQP_READ, ¤t_rtc_freq); @@ -1580,8 +1617,9 @@ static void dynticks_rearm_timer(struct qemu_alarm_timer *t) int64_t nearest_delta_us = INT64_MAX; int64_t current_us; - if (!active_timers[QEMU_TIMER_REALTIME] && - !active_timers[QEMU_TIMER_VIRTUAL]) + if (!active_timers[QEMU_CLOCK_REALTIME] && + !active_timers[QEMU_CLOCK_VIRTUAL] && + !active_timers[QEMU_CLOCK_HOST]) return; nearest_delta_us = qemu_next_deadline_dyntick(); @@ -1675,7 +1713,8 @@ static int win32_start_timer(struct qemu_alarm_timer *t) flags); if (!data->timerId) { - perror("Failed to initialize win32 alarm timer"); + fprintf(stderr, "Failed to initialize win32 alarm timer: %ld\n", + GetLastError()); timeEndPeriod(data->period); return -1; } @@ -1694,15 +1733,12 @@ static void win32_stop_timer(struct qemu_alarm_timer *t) 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]) + if (!active_timers[QEMU_CLOCK_REALTIME] && + !active_timers[QEMU_CLOCK_VIRTUAL] && + !active_timers[QEMU_CLOCK_HOST]) return; - nearest_delta_us = qemu_next_deadline_dyntick(); - nearest_delta_us /= 1000; - timeKillEvent(data->timerId); data->timerId = timeSetEvent(1, @@ -1712,7 +1748,8 @@ static void win32_rearm_timer(struct qemu_alarm_timer *t) TIME_ONESHOT | TIME_PERIODIC); if (!data->timerId) { - perror("Failed to re-arm win32 alarm timer"); + fprintf(stderr, "Failed to re-arm win32 alarm timer %ld\n", + GetLastError()); timeEndPeriod(data->period); exit(1); @@ -3188,7 +3225,7 @@ static int ram_save_block(QEMUFile *f) return found; } -static uint64_t bytes_transferred = 0; +static uint64_t bytes_transferred; static ram_addr_t ram_save_remaining(void) { @@ -3231,6 +3268,8 @@ static int ram_save_live(QEMUFile *f, int stage, void *opaque) } if (stage == 1) { + bytes_transferred = 0; + /* Make sure all dirty bits are set */ for (addr = 0; addr < last_ram_offset; addr += TARGET_PAGE_SIZE) { if (!cpu_physical_memory_get_dirty(addr, MIGRATION_DIRTY_FLAG)) @@ -3244,7 +3283,7 @@ static int ram_save_live(QEMUFile *f, int stage, void *opaque) } bytes_transferred_last = bytes_transferred; - bwidth = get_clock(); + bwidth = qemu_get_clock_ns(rt_clock); while (!qemu_file_rate_limit(f)) { int ret; @@ -3255,7 +3294,7 @@ static int ram_save_live(QEMUFile *f, int stage, void *opaque) break; } - bwidth = get_clock() - bwidth; + bwidth = qemu_get_clock_ns(rt_clock) - bwidth; bwidth = (bytes_transferred - bytes_transferred_last) / bwidth; /* if we haven't transferred anything this round, force expected_time to a @@ -3264,9 +3303,7 @@ static int ram_save_live(QEMUFile *f, int stage, void *opaque) bwidth = 0.000001; /* try transferring iterative blocks of memory */ - if (stage == 3) { - /* flush all remaining blocks regardless of rate limiting */ while (ram_save_block(f) != 0) { bytes_transferred += TARGET_PAGE_SIZE; @@ -3780,6 +3817,8 @@ static int cpu_can_run(CPUState *env) return 0; if (env->stopped) return 0; + if (!vm_running) + return 0; return 1; } @@ -3822,10 +3861,6 @@ void qemu_notify_event(void) if (env) { cpu_exit(env); -#ifdef USE_KQEMU - if (env->kqemu_enabled) - kqemu_cpu_interrupt(env); -#endif } } @@ -4290,14 +4325,17 @@ void main_loop_wait(int timeout) /* vm time timers */ if (vm_running) { if (!cur_cpu || likely(!(cur_cpu->singlestep_enabled & SSTEP_NOTIMER))) - qemu_run_timers(&active_timers[QEMU_TIMER_VIRTUAL], + qemu_run_timers(&active_timers[QEMU_CLOCK_VIRTUAL], qemu_get_clock(vm_clock)); } /* real time timers */ - qemu_run_timers(&active_timers[QEMU_TIMER_REALTIME], + qemu_run_timers(&active_timers[QEMU_CLOCK_REALTIME], qemu_get_clock(rt_clock)); + qemu_run_timers(&active_timers[QEMU_CLOCK_HOST], + qemu_get_clock(host_clock)); + /* Check bottom-halves last in case any of the earlier events triggered them. */ qemu_bh_poll(); @@ -4353,14 +4391,15 @@ static void tcg_cpu_exec(void) for (; next_cpu != NULL; next_cpu = next_cpu->next_cpu) { CPUState *env = cur_cpu = next_cpu; - if (!vm_running) - break; if (timer_alarm_pending) { timer_alarm_pending = 0; break; } if (cpu_can_run(env)) ret = qemu_cpu_exec(env); + else if (env->stop) + break; + if (ret == EXCP_DEBUG) { gdb_set_stop_cpu(env); debug_requested = 1; @@ -4982,6 +5021,8 @@ int main(int argc, char **argv, char **envp) CPUState *env; int show_vnc_port = 0; + init_clocks(); + qemu_cache_utils_init(envp); QLIST_INIT (&vm_change_state_head); @@ -5819,7 +5860,6 @@ int main(int argc, char **argv, char **envp) } setvbuf(stdout, NULL, _IOLBF, 0); - init_timers(); if (init_timer_alarm() < 0) { fprintf(stderr, "could not initialize alarm timer\n"); exit(1); @@ -6216,8 +6256,11 @@ int main(int argc, char **argv, char **envp) if (len != 1) exit(1); - chdir("/"); - TFR(fd = open("/dev/null", O_RDWR)); + if (chdir("/")) { + perror("not able to chdir to /"); + exit(1); + } + TFR(fd = qemu_open("/dev/null", O_RDWR)); if (fd == -1) exit(1); } @@ -6235,7 +6278,10 @@ int main(int argc, char **argv, char **envp) fprintf(stderr, "chroot failed\n"); exit(1); } - chdir("/"); + if (chdir("/")) { + perror("not able to chdir to /"); + exit(1); + } } if (run_as) { -- cgit v1.1