Commit efe75411ec7113294810ca7abc52ac400505e96d

Authored by ths
1 parent f3dcfada

Add support for dynamic ticks, by Luca Tettamanti and Dan Kenigsberg.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3130 c046a42c-6fe2-441c-8c8c-71466251a162
Showing 1 changed file with 177 additions and 8 deletions
... ... @@ -784,12 +784,32 @@ struct QEMUTimer {
784 784  
785 785 struct qemu_alarm_timer {
786 786 char const *name;
  787 + unsigned int flags;
787 788  
788 789 int (*start)(struct qemu_alarm_timer *t);
789 790 void (*stop)(struct qemu_alarm_timer *t);
  791 + void (*rearm)(struct qemu_alarm_timer *t);
790 792 void *priv;
791 793 };
792 794  
  795 +#define ALARM_FLAG_DYNTICKS 0x1
  796 +
  797 +static inline int alarm_has_dynticks(struct qemu_alarm_timer *t)
  798 +{
  799 + return t->flags & ALARM_FLAG_DYNTICKS;
  800 +}
  801 +
  802 +static void qemu_rearm_alarm_timer(struct qemu_alarm_timer *t)
  803 +{
  804 + if (!alarm_has_dynticks(t))
  805 + return;
  806 +
  807 + t->rearm(t);
  808 +}
  809 +
  810 +/* TODO: MIN_TIMER_REARM_US should be optimized */
  811 +#define MIN_TIMER_REARM_US 250
  812 +
793 813 static struct qemu_alarm_timer *alarm_timer;
794 814  
795 815 #ifdef _WIN32
... ... @@ -802,12 +822,17 @@ struct qemu_alarm_win32 {
802 822  
803 823 static int win32_start_timer(struct qemu_alarm_timer *t);
804 824 static void win32_stop_timer(struct qemu_alarm_timer *t);
  825 +static void win32_rearm_timer(struct qemu_alarm_timer *t);
805 826  
806 827 #else
807 828  
808 829 static int unix_start_timer(struct qemu_alarm_timer *t);
809 830 static void unix_stop_timer(struct qemu_alarm_timer *t);
810 831  
  832 +static int dynticks_start_timer(struct qemu_alarm_timer *t);
  833 +static void dynticks_stop_timer(struct qemu_alarm_timer *t);
  834 +static void dynticks_rearm_timer(struct qemu_alarm_timer *t);
  835 +
811 836 #ifdef __linux__
812 837  
813 838 static int hpet_start_timer(struct qemu_alarm_timer *t);
... ... @@ -816,21 +841,26 @@ static void hpet_stop_timer(struct qemu_alarm_timer *t);
816 841 static int rtc_start_timer(struct qemu_alarm_timer *t);
817 842 static void rtc_stop_timer(struct qemu_alarm_timer *t);
818 843  
819   -#endif
  844 +#endif /* __linux__ */
820 845  
821 846 #endif /* _WIN32 */
822 847  
823 848 static struct qemu_alarm_timer alarm_timers[] = {
  849 +#ifndef _WIN32
  850 + {"dynticks", ALARM_FLAG_DYNTICKS, dynticks_start_timer,
  851 + dynticks_stop_timer, dynticks_rearm_timer, NULL},
824 852 #ifdef __linux__
825 853 /* HPET - if available - is preferred */
826   - {"hpet", hpet_start_timer, hpet_stop_timer, NULL},
  854 + {"hpet", 0, hpet_start_timer, hpet_stop_timer, NULL, NULL},
827 855 /* ...otherwise try RTC */
828   - {"rtc", rtc_start_timer, rtc_stop_timer, NULL},
  856 + {"rtc", 0, rtc_start_timer, rtc_stop_timer, NULL, NULL},
829 857 #endif
830   -#ifndef _WIN32
831   - {"unix", unix_start_timer, unix_stop_timer, NULL},
  858 + {"unix", 0, unix_start_timer, unix_stop_timer, NULL, NULL},
832 859 #else
833   - {"win32", win32_start_timer, win32_stop_timer, &alarm_win32_data},
  860 + {"dynticks", ALARM_FLAG_DYNTICKS, win32_start_timer,
  861 + win32_stop_timer, win32_rearm_timer, &alarm_win32_data},
  862 + {"win32", 0, win32_start_timer,
  863 + win32_stop_timer, NULL, &alarm_win32_data},
834 864 #endif
835 865 {NULL, }
836 866 };
... ... @@ -949,6 +979,8 @@ void qemu_del_timer(QEMUTimer *ts)
949 979 }
950 980 pt = &t->next;
951 981 }
  982 +
  983 + qemu_rearm_alarm_timer(alarm_timer);
952 984 }
953 985  
954 986 /* modify the current timer so that it will be fired when current_time
... ... @@ -1008,6 +1040,7 @@ static void qemu_run_timers(QEMUTimer **ptimer_head, int64_t current_time)
1008 1040 /* run the callback (the timer list can be modified) */
1009 1041 ts->cb(ts->opaque);
1010 1042 }
  1043 + qemu_rearm_alarm_timer(alarm_timer);
1011 1044 }
1012 1045  
1013 1046 int64_t qemu_get_clock(QEMUClock *clock)
... ... @@ -1115,7 +1148,8 @@ static void host_alarm_handler(int host_signum)
1115 1148 last_clock = ti;
1116 1149 }
1117 1150 #endif
1118   - if (qemu_timer_expired(active_timers[QEMU_TIMER_VIRTUAL],
  1151 + if (alarm_has_dynticks(alarm_timer) ||
  1152 + qemu_timer_expired(active_timers[QEMU_TIMER_VIRTUAL],
1119 1153 qemu_get_clock(vm_clock)) ||
1120 1154 qemu_timer_expired(active_timers[QEMU_TIMER_REALTIME],
1121 1155 qemu_get_clock(rt_clock))) {
... ... @@ -1136,6 +1170,30 @@ static void host_alarm_handler(int host_signum)
1136 1170 }
1137 1171 }
1138 1172  
  1173 +static uint64_t qemu_next_deadline(void)
  1174 +{
  1175 + int64_t nearest_delta_us = ULLONG_MAX;
  1176 + int64_t vmdelta_us;
  1177 +
  1178 + if (active_timers[QEMU_TIMER_REALTIME])
  1179 + nearest_delta_us = (active_timers[QEMU_TIMER_REALTIME]->expire_time -
  1180 + qemu_get_clock(rt_clock))*1000;
  1181 +
  1182 + if (active_timers[QEMU_TIMER_VIRTUAL]) {
  1183 + /* round up */
  1184 + vmdelta_us = (active_timers[QEMU_TIMER_VIRTUAL]->expire_time -
  1185 + qemu_get_clock(vm_clock)+999)/1000;
  1186 + if (vmdelta_us < nearest_delta_us)
  1187 + nearest_delta_us = vmdelta_us;
  1188 + }
  1189 +
  1190 + /* Avoid arming the timer to negative, zero, or too low values */
  1191 + if (nearest_delta_us <= MIN_TIMER_REARM_US)
  1192 + nearest_delta_us = MIN_TIMER_REARM_US;
  1193 +
  1194 + return nearest_delta_us;
  1195 +}
  1196 +
1139 1197 #ifndef _WIN32
1140 1198  
1141 1199 #if defined(__linux__)
... ... @@ -1243,6 +1301,80 @@ static void rtc_stop_timer(struct qemu_alarm_timer *t)
1243 1301  
1244 1302 #endif /* !defined(__linux__) */
1245 1303  
  1304 +static int dynticks_start_timer(struct qemu_alarm_timer *t)
  1305 +{
  1306 + struct sigevent ev;
  1307 + timer_t host_timer;
  1308 + struct sigaction act;
  1309 +
  1310 + sigfillset(&act.sa_mask);
  1311 + act.sa_flags = 0;
  1312 +#if defined(TARGET_I386) && defined(USE_CODE_COPY)
  1313 + act.sa_flags |= SA_ONSTACK;
  1314 +#endif
  1315 + act.sa_handler = host_alarm_handler;
  1316 +
  1317 + sigaction(SIGALRM, &act, NULL);
  1318 +
  1319 + ev.sigev_value.sival_int = 0;
  1320 + ev.sigev_notify = SIGEV_SIGNAL;
  1321 + ev.sigev_signo = SIGALRM;
  1322 +
  1323 + if (timer_create(CLOCK_REALTIME, &ev, &host_timer)) {
  1324 + perror("timer_create");
  1325 +
  1326 + /* disable dynticks */
  1327 + fprintf(stderr, "Dynamic Ticks disabled\n");
  1328 +
  1329 + return -1;
  1330 + }
  1331 +
  1332 + t->priv = (void *)host_timer;
  1333 +
  1334 + return 0;
  1335 +}
  1336 +
  1337 +static void dynticks_stop_timer(struct qemu_alarm_timer *t)
  1338 +{
  1339 + timer_t host_timer = (timer_t)t->priv;
  1340 +
  1341 + timer_delete(host_timer);
  1342 +}
  1343 +
  1344 +static void dynticks_rearm_timer(struct qemu_alarm_timer *t)
  1345 +{
  1346 + timer_t host_timer = (timer_t)t->priv;
  1347 + struct itimerspec timeout;
  1348 + int64_t nearest_delta_us = INT64_MAX;
  1349 + int64_t current_us;
  1350 +
  1351 + if (!active_timers[QEMU_TIMER_REALTIME] &&
  1352 + !active_timers[QEMU_TIMER_VIRTUAL])
  1353 + return;
  1354 +
  1355 + nearest_delta_us = qemu_next_deadline();
  1356 +
  1357 + /* check whether a timer is already running */
  1358 + if (timer_gettime(host_timer, &timeout)) {
  1359 + perror("gettime");
  1360 + fprintf(stderr, "Internal timer error: aborting\n");
  1361 + exit(1);
  1362 + }
  1363 + current_us = timeout.it_value.tv_sec * 1000000 + timeout.it_value.tv_nsec/1000;
  1364 + if (current_us && current_us <= nearest_delta_us)
  1365 + return;
  1366 +
  1367 + timeout.it_interval.tv_sec = 0;
  1368 + timeout.it_interval.tv_nsec = 0; /* 0 for one-shot timer */
  1369 + timeout.it_value.tv_sec = nearest_delta_us / 1000000;
  1370 + timeout.it_value.tv_nsec = (nearest_delta_us % 1000000) * 1000;
  1371 + if (timer_settime(host_timer, 0 /* RELATIVE */, &timeout, NULL)) {
  1372 + perror("settime");
  1373 + fprintf(stderr, "Internal timer error: aborting\n");
  1374 + exit(1);
  1375 + }
  1376 +}
  1377 +
1246 1378 static int unix_start_timer(struct qemu_alarm_timer *t)
1247 1379 {
1248 1380 struct sigaction act;
... ... @@ -1288,6 +1420,7 @@ static int win32_start_timer(struct qemu_alarm_timer *t)
1288 1420 {
1289 1421 TIMECAPS tc;
1290 1422 struct qemu_alarm_win32 *data = t->priv;
  1423 + UINT flags;
1291 1424  
1292 1425 data->host_alarm = CreateEvent(NULL, FALSE, FALSE, NULL);
1293 1426 if (!data->host_alarm) {
... ... @@ -1303,11 +1436,17 @@ static int win32_start_timer(struct qemu_alarm_timer *t)
1303 1436  
1304 1437 timeBeginPeriod(data->period);
1305 1438  
  1439 + flags = TIME_CALLBACK_FUNCTION;
  1440 + if (alarm_has_dynticks(t))
  1441 + flags |= TIME_ONESHOT;
  1442 + else
  1443 + flags |= TIME_PERIODIC;
  1444 +
1306 1445 data->timerId = timeSetEvent(1, // interval (ms)
1307 1446 data->period, // resolution
1308 1447 host_alarm_handler, // function
1309 1448 (DWORD)t, // parameter
1310   - TIME_PERIODIC | TIME_CALLBACK_FUNCTION);
  1449 + flags);
1311 1450  
1312 1451 if (!data->timerId) {
1313 1452 perror("Failed to initialize win32 alarm timer");
... ... @@ -1332,6 +1471,35 @@ static void win32_stop_timer(struct qemu_alarm_timer *t)
1332 1471 CloseHandle(data->host_alarm);
1333 1472 }
1334 1473  
  1474 +static void win32_rearm_timer(struct qemu_alarm_timer *t)
  1475 +{
  1476 + struct qemu_alarm_win32 *data = t->priv;
  1477 + uint64_t nearest_delta_us;
  1478 +
  1479 + if (!active_timers[QEMU_TIMER_REALTIME] &&
  1480 + !active_timers[QEMU_TIMER_VIRTUAL])
  1481 + return;
  1482 +
  1483 + nearest_delta_us = qemu_next_deadline();
  1484 + nearest_delta_us /= 1000;
  1485 +
  1486 + timeKillEvent(data->timerId);
  1487 +
  1488 + data->timerId = timeSetEvent(1,
  1489 + data->period,
  1490 + host_alarm_handler,
  1491 + (DWORD)t,
  1492 + TIME_ONESHOT | TIME_PERIODIC);
  1493 +
  1494 + if (!data->timerId) {
  1495 + perror("Failed to re-arm win32 alarm timer");
  1496 +
  1497 + timeEndPeriod(data->period);
  1498 + CloseHandle(data->host_alarm);
  1499 + exit(1);
  1500 + }
  1501 +}
  1502 +
1335 1503 #endif /* _WIN32 */
1336 1504  
1337 1505 static void init_timer_alarm(void)
... ... @@ -6490,6 +6658,7 @@ void vm_start(void)
6490 6658 cpu_enable_ticks();
6491 6659 vm_running = 1;
6492 6660 vm_state_notify(1);
  6661 + qemu_rearm_alarm_timer(alarm_timer);
6493 6662 }
6494 6663 }
6495 6664  
... ...