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,19 +781,59 @@ struct QEMUTimer {
781 struct QEMUTimer *next; 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 #ifdef _WIN32 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 #else 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 #endif 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 QEMUClock *qemu_new_clock(int type) 837 QEMUClock *qemu_new_clock(int type)
798 { 838 {
799 QEMUClock *clock; 839 QEMUClock *clock;
@@ -1009,7 +1049,8 @@ static void host_alarm_handler(int host_signum) @@ -1009,7 +1049,8 @@ static void host_alarm_handler(int host_signum)
1009 qemu_timer_expired(active_timers[QEMU_TIMER_REALTIME], 1049 qemu_timer_expired(active_timers[QEMU_TIMER_REALTIME],
1010 qemu_get_clock(rt_clock))) { 1050 qemu_get_clock(rt_clock))) {
1011 #ifdef _WIN32 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 #endif 1054 #endif
1014 CPUState *env = cpu_single_env; 1055 CPUState *env = cpu_single_env;
1015 if (env) { 1056 if (env) {
@@ -1030,10 +1071,27 @@ static void host_alarm_handler(int host_signum) @@ -1030,10 +1071,27 @@ static void host_alarm_handler(int host_signum)
1030 1071
1031 #define RTC_FREQ 1024 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 TFR(rtc_fd = open("/dev/rtc", O_RDONLY)); 1095 TFR(rtc_fd = open("/dev/rtc", O_RDONLY));
1038 if (rtc_fd < 0) 1096 if (rtc_fd < 0)
1039 return -1; 1097 return -1;
@@ -1048,117 +1106,142 @@ static int start_rtc_timer(void) @@ -1048,117 +1106,142 @@ static int start_rtc_timer(void)
1048 close(rtc_fd); 1106 close(rtc_fd);
1049 return -1; 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 return 0; 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 #endif /* !defined(__linux__) */ 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 #ifdef _WIN32 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,7 +447,6 @@ void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time);
447 int qemu_timer_pending(QEMUTimer *ts); 447 int qemu_timer_pending(QEMUTimer *ts);
448 448
449 extern int64_t ticks_per_sec; 449 extern int64_t ticks_per_sec;
450 -extern int pit_min_timer_count;  
451 450
452 int64_t cpu_get_ticks(void); 451 int64_t cpu_get_ticks(void);
453 void cpu_enable_ticks(void); 452 void cpu_enable_ticks(void);