Commit c89940133c02810197c405814439b0d529e5d551

Authored by ths
1 parent 7603d156

Rework alarm timer infrastrucure, by Luca Tettamanti.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3125 c046a42c-6fe2-441c-8c8c-71466251a162
Showing 2 changed files with 186 additions and 104 deletions
... ... @@ -781,19 +781,59 @@ struct QEMUTimer {
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,7 +1049,8 @@ static void host_alarm_handler(int host_signum)
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,10 +1071,27 @@ static void host_alarm_handler(int host_signum)
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,117 +1106,142 @@ static int start_rtc_timer(void)
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 /***********************************************************/
... ...
... ... @@ -447,7 +447,6 @@ void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time);
447 447 int qemu_timer_pending(QEMUTimer *ts);
448 448  
449 449 extern int64_t ticks_per_sec;
450   -extern int pit_min_timer_count;
451 450  
452 451 int64_t cpu_get_ticks(void);
453 452 void cpu_enable_ticks(void);
... ...