Make the alarm code modular, removing #ifdef from the generic code and abstract a common interface for all the timer. The result is functionally equivalent to the old code.
Signed-off-by: Luca Tettamanti <[EMAIL PROTECTED]> --- qemu/vl.c | 292 +++++++++++++++++++++++++++++++++------------------ 1 files changed, 189 insertions(+), 103 deletions(-) diff --git a/qemu/vl.c b/qemu/vl.c index 5360ed7..33443ca 100644 --- a/qemu/vl.c +++ b/qemu/vl.c @@ -745,18 +745,58 @@ struct QEMUTimer { struct QEMUTimer *next; }; -QEMUClock *rt_clock; -QEMUClock *vm_clock; +struct qemu_alarm_timer { + char const *name; + + int (*start)(struct qemu_alarm_timer *t); + void (*stop)(struct qemu_alarm_timer *t); + void *priv; +}; + +static struct qemu_alarm_timer *alarm_timer; -static QEMUTimer *active_timers[2]; #ifdef _WIN32 -static MMRESULT timerID; -static HANDLE host_alarm = NULL; -static unsigned int period = 1; + +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); + +#else + +static int unix_start_timer(struct qemu_alarm_timer *t); +static void unix_stop_timer(struct qemu_alarm_timer *t); + +#ifdef __linux__ + +static int rtc_start_timer(struct qemu_alarm_timer *t); +static void rtc_stop_timer(struct qemu_alarm_timer *t); + +#endif + +#endif /* _WIN32 */ + +static struct qemu_alarm_timer alarm_timers[] = { +#ifdef __linux__ + /* RTC - if available - is preferred */ + {"rtc", rtc_start_timer, rtc_stop_timer, NULL}, +#endif +#ifndef _WIN32 + {"unix", unix_start_timer, unix_stop_timer, NULL}, #else -/* frequency of the times() clock tick */ -static int timer_freq; + {"win32", win32_start_timer, win32_stop_timer, &alarm_win32_data}, #endif + {NULL, } +}; + +QEMUClock *rt_clock; +QEMUClock *vm_clock; + +static QEMUTimer *active_timers[2]; QEMUClock *qemu_new_clock(int type) { @@ -973,7 +1013,8 @@ static void host_alarm_handler(int host_signum) qemu_timer_expired(active_timers[QEMU_TIMER_REALTIME], qemu_get_clock(rt_clock))) { #ifdef _WIN32 - SetEvent(host_alarm); + struct qemu_alarm_win32 *data = ((struct qemu_alarm_timer*)dwUser)->priv; + SetEvent(data->host_alarm); #endif CPUState *env = cpu_single_env; if (env) { @@ -995,10 +1036,31 @@ static void host_alarm_handler(int host_signum) #define RTC_FREQ 1024 static int use_rtc = 1; -static int rtc_fd; -static int start_rtc_timer(void) +static void enable_sigio_timer(int fd) +{ + struct sigaction act; + + /* timer signal */ + sigfillset(&act.sa_mask); + act.sa_flags = 0; +#if defined (TARGET_I386) && defined(USE_CODE_COPY) + act.sa_flags |= SA_ONSTACK; +#endif + act.sa_handler = host_alarm_handler; + + sigaction(SIGIO, &act, NULL); + fcntl(fd, F_SETFL, O_ASYNC); + fcntl(fd, F_SETOWN, getpid()); +} + +static int rtc_start_timer(struct qemu_alarm_timer *t) { + int rtc_fd; + + if (!use_rtc) + return -1; + rtc_fd = open("/dev/rtc", O_RDONLY); if (rtc_fd < 0) return -1; @@ -1009,121 +1071,145 @@ static int start_rtc_timer(void) goto fail; } if (ioctl(rtc_fd, RTC_PIE_ON, 0) < 0) { - fail: +fail: close(rtc_fd); return -1; } - pit_min_timer_count = PIT_FREQ / RTC_FREQ; + + enable_sigio_timer(rtc_fd); + + t->priv = (void *)rtc_fd; + return 0; } -#else - -static int start_rtc_timer(void) +static void rtc_stop_timer(struct qemu_alarm_timer *t) { - return -1; + int rtc_fd = (int)t->priv; + + close(rtc_fd); } #endif /* !defined(__linux__) */ -#endif /* !defined(_WIN32) */ +static int unix_start_timer(struct qemu_alarm_timer *t) +{ + struct sigaction act; + struct itimerval itv; + int err; -static void init_timer_alarm(void) + /* timer signal */ + sigfillset(&act.sa_mask); + act.sa_flags = 0; +#if defined(TARGET_I386) && defined(USE_CODE_COPY) + act.sa_flags |= SA_ONSTACK; +#endif + 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 /* !defined(_WIN32) */ + #ifdef _WIN32 - { - int count=0; - TIMECAPS tc; - - ZeroMemory(&tc, sizeof(TIMECAPS)); - timeGetDevCaps(&tc, sizeof(TIMECAPS)); - if (period < tc.wPeriodMin) - period = tc.wPeriodMin; - timeBeginPeriod(period); - timerID = timeSetEvent(1, // interval (ms) - period, // resolution - host_alarm_handler, // function - (DWORD)&count, // user parameter - TIME_PERIODIC | TIME_CALLBACK_FUNCTION); - if( !timerID ) { - perror("failed timer alarm"); - exit(1); - } - host_alarm = CreateEvent(NULL, FALSE, FALSE, NULL); - if (!host_alarm) { - perror("failed CreateEvent"); - exit(1); - } - qemu_add_wait_object(host_alarm, NULL, NULL); + +static int win32_start_timer(struct qemu_alarm_timer *t) +{ + TIMECAPS tc; + struct qemu_alarm_win32 *data = t->priv; + + data->host_alarm = CreateEvent(NULL, FALSE, FALSE, NULL); + if (!data->host_alarm) { + perror("Failed CreateEvent"); + return -1; } - pit_min_timer_count = ((uint64_t)10000 * PIT_FREQ) / 1000000; -#else - { - struct sigaction act; - struct itimerval itv; - - /* get times() syscall frequency */ - timer_freq = sysconf(_SC_CLK_TCK); - - /* timer signal */ - sigfillset(&act.sa_mask); - act.sa_flags = 0; -#if defined (TARGET_I386) && defined(USE_CODE_COPY) - act.sa_flags |= SA_ONSTACK; -#endif - act.sa_handler = host_alarm_handler; - sigaction(SIGALRM, &act, NULL); - itv.it_interval.tv_sec = 0; - itv.it_interval.tv_usec = 999; /* for i386 kernel 2.6 to get 1 ms */ - itv.it_value.tv_sec = 0; - itv.it_value.tv_usec = 10 * 1000; - setitimer(ITIMER_REAL, &itv, NULL); - /* we probe the tick duration of the kernel to inform the user if - the emulated kernel requested a too high timer frequency */ - getitimer(ITIMER_REAL, &itv); + memset(&tc, 0, sizeof(tc)); + timeGetDevCaps(&tc, sizeof(tc)); -#if defined(__linux__) - /* XXX: force /dev/rtc usage because even 2.6 kernels may not - have timers with 1 ms resolution. The correct solution will - be to use the POSIX real time timers available in recent - 2.6 kernels */ - if (itv.it_interval.tv_usec > 1000 || 1) { - /* try to use /dev/rtc to have a faster timer */ - if (!use_rtc || (start_rtc_timer() < 0)) - goto use_itimer; - /* disable itimer */ - itv.it_interval.tv_sec = 0; - itv.it_interval.tv_usec = 0; - itv.it_value.tv_sec = 0; - itv.it_value.tv_usec = 0; - setitimer(ITIMER_REAL, &itv, NULL); - - /* use the RTC */ - sigaction(SIGIO, &act, NULL); - fcntl(rtc_fd, F_SETFL, O_ASYNC); - fcntl(rtc_fd, F_SETOWN, getpid()); - } else -#endif /* defined(__linux__) */ - { - use_itimer: - pit_min_timer_count = ((uint64_t)itv.it_interval.tv_usec * - PIT_FREQ) / 1000000; - } + if (data->period < tc.wPeriodMin) + data->period = tc.wPeriodMin; + + timeBeginPeriod(data->period); + + data->timerId = timeSetEvent(1, // interval (ms) + data->period, // resolution + host_alarm_handler, // function + (DWORD)t, // parameter + TIME_PERIODIC | TIME_CALLBACK_FUNCTION); + + if (!data->timerId) { + perror("Failed to initialize win32 alarm timer"); + + 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 + +static void init_timer_alarm(void) +{ + struct qemu_alarm_timer *t; + int i, err = -1; + + for (i = 0; alarm_timers[i].name; i++) { + t = &alarm_timers[i]; + + printf("trying %s...\n", t->name); + + 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); + } + + alarm_timer = t; } void quit_timers(void) { -#ifdef _WIN32 - timeKillEvent(timerID); - timeEndPeriod(period); - if (host_alarm) { - CloseHandle(host_alarm); - host_alarm = NULL; - } -#endif + alarm_timer->stop(alarm_timer); + alarm_timer = NULL; } /***********************************************************/ -- 1.5.2.4