Revision efe75411
b/vl.c | ||
---|---|---|
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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 |
|
Also available in: Unified diff