Revision c8994013 vl.c
b/vl.c | ||
---|---|---|
781 | 781 |
struct QEMUTimer *next; |
782 | 782 |
}; |
783 | 783 |
|
784 |
QEMUClock *rt_clock; |
|
785 |
QEMUClock *vm_clock; |
|
784 |
struct qemu_alarm_timer { |
|
785 |
char const *name; |
|
786 |
|
|
787 |
int (*start)(struct qemu_alarm_timer *t); |
|
788 |
void (*stop)(struct qemu_alarm_timer *t); |
|
789 |
void *priv; |
|
790 |
}; |
|
791 |
|
|
792 |
static struct qemu_alarm_timer *alarm_timer; |
|
786 | 793 |
|
787 |
static QEMUTimer *active_timers[2]; |
|
788 | 794 |
#ifdef _WIN32 |
789 |
static MMRESULT timerID; |
|
790 |
static HANDLE host_alarm = NULL; |
|
791 |
static unsigned int period = 1; |
|
795 |
|
|
796 |
struct qemu_alarm_win32 { |
|
797 |
MMRESULT timerId; |
|
798 |
HANDLE host_alarm; |
|
799 |
unsigned int period; |
|
800 |
} alarm_win32_data = {0, NULL, -1}; |
|
801 |
|
|
802 |
static int win32_start_timer(struct qemu_alarm_timer *t); |
|
803 |
static void win32_stop_timer(struct qemu_alarm_timer *t); |
|
804 |
|
|
792 | 805 |
#else |
793 |
/* frequency of the times() clock tick */ |
|
794 |
static int timer_freq; |
|
806 |
|
|
807 |
static int unix_start_timer(struct qemu_alarm_timer *t); |
|
808 |
static void unix_stop_timer(struct qemu_alarm_timer *t); |
|
809 |
|
|
810 |
#ifdef __linux__ |
|
811 |
|
|
812 |
static int rtc_start_timer(struct qemu_alarm_timer *t); |
|
813 |
static void rtc_stop_timer(struct qemu_alarm_timer *t); |
|
814 |
|
|
795 | 815 |
#endif |
796 | 816 |
|
817 |
#endif /* _WIN32 */ |
|
818 |
|
|
819 |
static struct qemu_alarm_timer alarm_timers[] = { |
|
820 |
#ifdef __linux__ |
|
821 |
/* RTC - if available - is preferred */ |
|
822 |
{"rtc", rtc_start_timer, rtc_stop_timer, NULL}, |
|
823 |
#endif |
|
824 |
#ifndef _WIN32 |
|
825 |
{"unix", unix_start_timer, unix_stop_timer, NULL}, |
|
826 |
#else |
|
827 |
{"win32", win32_start_timer, win32_stop_timer, &alarm_win32_data}, |
|
828 |
#endif |
|
829 |
{NULL, } |
|
830 |
}; |
|
831 |
|
|
832 |
QEMUClock *rt_clock; |
|
833 |
QEMUClock *vm_clock; |
|
834 |
|
|
835 |
static QEMUTimer *active_timers[2]; |
|
836 |
|
|
797 | 837 |
QEMUClock *qemu_new_clock(int type) |
798 | 838 |
{ |
799 | 839 |
QEMUClock *clock; |
... | ... | |
1009 | 1049 |
qemu_timer_expired(active_timers[QEMU_TIMER_REALTIME], |
1010 | 1050 |
qemu_get_clock(rt_clock))) { |
1011 | 1051 |
#ifdef _WIN32 |
1012 |
SetEvent(host_alarm); |
|
1052 |
struct qemu_alarm_win32 *data = ((struct qemu_alarm_timer*)dwUser)->priv; |
|
1053 |
SetEvent(data->host_alarm); |
|
1013 | 1054 |
#endif |
1014 | 1055 |
CPUState *env = cpu_single_env; |
1015 | 1056 |
if (env) { |
... | ... | |
1030 | 1071 |
|
1031 | 1072 |
#define RTC_FREQ 1024 |
1032 | 1073 |
|
1033 |
static int rtc_fd; |
|
1074 |
static void enable_sigio_timer(int fd) |
|
1075 |
{ |
|
1076 |
struct sigaction act; |
|
1034 | 1077 |
|
1035 |
static int start_rtc_timer(void) |
|
1078 |
/* timer signal */ |
|
1079 |
sigfillset(&act.sa_mask); |
|
1080 |
act.sa_flags = 0; |
|
1081 |
#if defined (TARGET_I386) && defined(USE_CODE_COPY) |
|
1082 |
act.sa_flags |= SA_ONSTACK; |
|
1083 |
#endif |
|
1084 |
act.sa_handler = host_alarm_handler; |
|
1085 |
|
|
1086 |
sigaction(SIGIO, &act, NULL); |
|
1087 |
fcntl(fd, F_SETFL, O_ASYNC); |
|
1088 |
fcntl(fd, F_SETOWN, getpid()); |
|
1089 |
} |
|
1090 |
|
|
1091 |
static int rtc_start_timer(struct qemu_alarm_timer *t) |
|
1036 | 1092 |
{ |
1093 |
int rtc_fd; |
|
1094 |
|
|
1037 | 1095 |
TFR(rtc_fd = open("/dev/rtc", O_RDONLY)); |
1038 | 1096 |
if (rtc_fd < 0) |
1039 | 1097 |
return -1; |
... | ... | |
1048 | 1106 |
close(rtc_fd); |
1049 | 1107 |
return -1; |
1050 | 1108 |
} |
1051 |
pit_min_timer_count = PIT_FREQ / RTC_FREQ; |
|
1109 |
|
|
1110 |
enable_sigio_timer(rtc_fd); |
|
1111 |
|
|
1112 |
t->priv = (void *)rtc_fd; |
|
1113 |
|
|
1052 | 1114 |
return 0; |
1053 | 1115 |
} |
1054 | 1116 |
|
1055 |
#else |
|
1056 |
|
|
1057 |
static int start_rtc_timer(void) |
|
1117 |
static void rtc_stop_timer(struct qemu_alarm_timer *t) |
|
1058 | 1118 |
{ |
1059 |
return -1; |
|
1119 |
int rtc_fd = (int)t->priv; |
|
1120 |
|
|
1121 |
close(rtc_fd); |
|
1060 | 1122 |
} |
1061 | 1123 |
|
1062 | 1124 |
#endif /* !defined(__linux__) */ |
1063 | 1125 |
|
1064 |
#endif /* !defined(_WIN32) */ |
|
1126 |
static int unix_start_timer(struct qemu_alarm_timer *t) |
|
1127 |
{ |
|
1128 |
struct sigaction act; |
|
1129 |
struct itimerval itv; |
|
1130 |
int err; |
|
1065 | 1131 |
|
1066 |
static void init_timer_alarm(void) |
|
1132 |
/* timer signal */ |
|
1133 |
sigfillset(&act.sa_mask); |
|
1134 |
act.sa_flags = 0; |
|
1135 |
#if defined(TARGET_I386) && defined(USE_CODE_COPY) |
|
1136 |
act.sa_flags |= SA_ONSTACK; |
|
1137 |
#endif |
|
1138 |
act.sa_handler = host_alarm_handler; |
|
1139 |
|
|
1140 |
sigaction(SIGALRM, &act, NULL); |
|
1141 |
|
|
1142 |
itv.it_interval.tv_sec = 0; |
|
1143 |
/* for i386 kernel 2.6 to get 1 ms */ |
|
1144 |
itv.it_interval.tv_usec = 999; |
|
1145 |
itv.it_value.tv_sec = 0; |
|
1146 |
itv.it_value.tv_usec = 10 * 1000; |
|
1147 |
|
|
1148 |
err = setitimer(ITIMER_REAL, &itv, NULL); |
|
1149 |
if (err) |
|
1150 |
return -1; |
|
1151 |
|
|
1152 |
return 0; |
|
1153 |
} |
|
1154 |
|
|
1155 |
static void unix_stop_timer(struct qemu_alarm_timer *t) |
|
1067 | 1156 |
{ |
1157 |
struct itimerval itv; |
|
1158 |
|
|
1159 |
memset(&itv, 0, sizeof(itv)); |
|
1160 |
setitimer(ITIMER_REAL, &itv, NULL); |
|
1161 |
} |
|
1162 |
|
|
1163 |
#endif /* !defined(_WIN32) */ |
|
1164 |
|
|
1068 | 1165 |
#ifdef _WIN32 |
1069 |
{ |
|
1070 |
int count=0; |
|
1071 |
TIMECAPS tc; |
|
1072 |
|
|
1073 |
ZeroMemory(&tc, sizeof(TIMECAPS)); |
|
1074 |
timeGetDevCaps(&tc, sizeof(TIMECAPS)); |
|
1075 |
if (period < tc.wPeriodMin) |
|
1076 |
period = tc.wPeriodMin; |
|
1077 |
timeBeginPeriod(period); |
|
1078 |
timerID = timeSetEvent(1, // interval (ms) |
|
1079 |
period, // resolution |
|
1080 |
host_alarm_handler, // function |
|
1081 |
(DWORD)&count, // user parameter |
|
1082 |
TIME_PERIODIC | TIME_CALLBACK_FUNCTION); |
|
1083 |
if( !timerID ) { |
|
1084 |
perror("failed timer alarm"); |
|
1085 |
exit(1); |
|
1086 |
} |
|
1087 |
host_alarm = CreateEvent(NULL, FALSE, FALSE, NULL); |
|
1088 |
if (!host_alarm) { |
|
1089 |
perror("failed CreateEvent"); |
|
1090 |
exit(1); |
|
1091 |
} |
|
1092 |
qemu_add_wait_object(host_alarm, NULL, NULL); |
|
1166 |
|
|
1167 |
static int win32_start_timer(struct qemu_alarm_timer *t) |
|
1168 |
{ |
|
1169 |
TIMECAPS tc; |
|
1170 |
struct qemu_alarm_win32 *data = t->priv; |
|
1171 |
|
|
1172 |
data->host_alarm = CreateEvent(NULL, FALSE, FALSE, NULL); |
|
1173 |
if (!data->host_alarm) { |
|
1174 |
perror("Failed CreateEvent"); |
|
1175 |
return -1 |
|
1093 | 1176 |
} |
1094 |
pit_min_timer_count = ((uint64_t)10000 * PIT_FREQ) / 1000000; |
|
1095 |
#else |
|
1096 |
{ |
|
1097 |
struct sigaction act; |
|
1098 |
struct itimerval itv; |
|
1099 |
|
|
1100 |
/* get times() syscall frequency */ |
|
1101 |
timer_freq = sysconf(_SC_CLK_TCK); |
|
1102 |
|
|
1103 |
/* timer signal */ |
|
1104 |
sigfillset(&act.sa_mask); |
|
1105 |
act.sa_flags = 0; |
|
1106 |
#if defined (TARGET_I386) && defined(USE_CODE_COPY) |
|
1107 |
act.sa_flags |= SA_ONSTACK; |
|
1108 |
#endif |
|
1109 |
act.sa_handler = host_alarm_handler; |
|
1110 |
sigaction(SIGALRM, &act, NULL); |
|
1111 | 1177 |
|
1112 |
itv.it_interval.tv_sec = 0; |
|
1113 |
itv.it_interval.tv_usec = 999; /* for i386 kernel 2.6 to get 1 ms */ |
|
1114 |
itv.it_value.tv_sec = 0; |
|
1115 |
itv.it_value.tv_usec = 10 * 1000; |
|
1116 |
setitimer(ITIMER_REAL, &itv, NULL); |
|
1117 |
/* we probe the tick duration of the kernel to inform the user if |
|
1118 |
the emulated kernel requested a too high timer frequency */ |
|
1119 |
getitimer(ITIMER_REAL, &itv); |
|
1178 |
memset(&tc, 0, sizeof(tc)); |
|
1179 |
timeGetDevCaps(&tc, sizeof(tc)); |
|
1120 | 1180 |
|
1121 |
#if defined(__linux__) |
|
1122 |
/* XXX: force /dev/rtc usage because even 2.6 kernels may not |
|
1123 |
have timers with 1 ms resolution. The correct solution will |
|
1124 |
be to use the POSIX real time timers available in recent |
|
1125 |
2.6 kernels */ |
|
1126 |
if (itv.it_interval.tv_usec > 1000 || 1) { |
|
1127 |
/* try to use /dev/rtc to have a faster timer */ |
|
1128 |
if (start_rtc_timer() < 0) |
|
1129 |
goto use_itimer; |
|
1130 |
/* disable itimer */ |
|
1131 |
itv.it_interval.tv_sec = 0; |
|
1132 |
itv.it_interval.tv_usec = 0; |
|
1133 |
itv.it_value.tv_sec = 0; |
|
1134 |
itv.it_value.tv_usec = 0; |
|
1135 |
setitimer(ITIMER_REAL, &itv, NULL); |
|
1136 |
|
|
1137 |
/* use the RTC */ |
|
1138 |
sigaction(SIGIO, &act, NULL); |
|
1139 |
fcntl(rtc_fd, F_SETFL, O_ASYNC); |
|
1140 |
fcntl(rtc_fd, F_SETOWN, getpid()); |
|
1141 |
} else |
|
1142 |
#endif /* defined(__linux__) */ |
|
1143 |
{ |
|
1144 |
use_itimer: |
|
1145 |
pit_min_timer_count = ((uint64_t)itv.it_interval.tv_usec * |
|
1146 |
PIT_FREQ) / 1000000; |
|
1147 |
} |
|
1181 |
if (data->period < tc.wPeriodMin) |
|
1182 |
data->period = tc.wPeriodMin; |
|
1183 |
|
|
1184 |
timeBeginPeriod(data->period); |
|
1185 |
|
|
1186 |
data->timerId = timeSetEvent(1, // interval (ms) |
|
1187 |
data->period, // resolution |
|
1188 |
host_alarm_handler, // function |
|
1189 |
(DWORD)t, // parameter |
|
1190 |
TIME_PERIODIC | TIME_CALLBACK_FUNCTION); |
|
1191 |
|
|
1192 |
if (!data->timerId) { |
|
1193 |
perror("Failed to initialize win32 alarm timer"); |
|
1194 |
|
|
1195 |
timeEndPeriod(data->period); |
|
1196 |
CloseHandle(data->host_alarm); |
|
1197 |
return -1; |
|
1148 | 1198 |
} |
1149 |
#endif |
|
1199 |
|
|
1200 |
qemu_add_wait_object(data->host_alarm, NULL, NULL); |
|
1201 |
|
|
1202 |
return 0; |
|
1150 | 1203 |
} |
1151 | 1204 |
|
1152 |
void quit_timers(void)
|
|
1205 |
static void win32_stop_timer(struct qemu_alarm_timer *t)
|
|
1153 | 1206 |
{ |
1154 |
#ifdef _WIN32 |
|
1155 |
timeKillEvent(timerID); |
|
1156 |
timeEndPeriod(period); |
|
1157 |
if (host_alarm) { |
|
1158 |
CloseHandle(host_alarm); |
|
1159 |
host_alarm = NULL; |
|
1207 |
struct qemu_alarm_win32 *data = t->priv; |
|
1208 |
|
|
1209 |
timeKillEvent(data->timerId); |
|
1210 |
timeEndPeriod(data->period); |
|
1211 |
|
|
1212 |
CloseHandle(data->host_alarm); |
|
1213 |
} |
|
1214 |
|
|
1215 |
#endif /* _WIN32 */ |
|
1216 |
|
|
1217 |
static void init_timer_alarm(void) |
|
1218 |
{ |
|
1219 |
struct qemu_alarm_timer *t; |
|
1220 |
int i, err = -1; |
|
1221 |
|
|
1222 |
for (i = 0; alarm_timers[i].name; i++) { |
|
1223 |
t = &alarm_timers[i]; |
|
1224 |
|
|
1225 |
printf("trying %s...\n", t->name); |
|
1226 |
|
|
1227 |
err = t->start(t); |
|
1228 |
if (!err) |
|
1229 |
break; |
|
1160 | 1230 |
} |
1161 |
#endif |
|
1231 |
|
|
1232 |
if (err) { |
|
1233 |
fprintf(stderr, "Unable to find any suitable alarm timer.\n"); |
|
1234 |
fprintf(stderr, "Terminating\n"); |
|
1235 |
exit(1); |
|
1236 |
} |
|
1237 |
|
|
1238 |
alarm_timer = t; |
|
1239 |
} |
|
1240 |
|
|
1241 |
void quit_timers(void) |
|
1242 |
{ |
|
1243 |
alarm_timer->stop(alarm_timer); |
|
1244 |
alarm_timer = NULL; |
|
1162 | 1245 |
} |
1163 | 1246 |
|
1164 | 1247 |
/***********************************************************/ |
Also available in: Unified diff