Commit c96f1a48d229a6080fecce4ea20bc64cabe79e32
1 parent
ffd39257
Fix alarm_timer race with select - v3 (Jan Kiszka)
Changing the default IO timeout to 5 s (#5578) made a race visible between the alarm_timer and select() in main_loop_wait(): If the timer fired before select was able to block, the full select() timeout could have been applied instead of returning immediately. Since #5578, this causes heavy problems to the Musicpal board emulation with stalls up to 5 s, but also with some older Linux guest kernels. The following patch introduces a pipe that is written to by host_alarm_handler and select()'ed in main_loop_wait(). This avoids prevents that select() blocks though a timer has fired and waits for processing. Signed-off-by: Jan Kiszka <jan.kiszka@web.de> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com> git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@5633 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
26 additions
and
2 deletions
vl.c
... | ... | @@ -885,6 +885,7 @@ static void qemu_rearm_alarm_timer(struct qemu_alarm_timer *t) |
885 | 885 | #define MIN_TIMER_REARM_US 250 |
886 | 886 | |
887 | 887 | static struct qemu_alarm_timer *alarm_timer; |
888 | +static int alarm_timer_rfd, alarm_timer_wfd; | |
888 | 889 | |
889 | 890 | #ifdef _WIN32 |
890 | 891 | |
... | ... | @@ -1304,12 +1305,15 @@ static void host_alarm_handler(int host_signum) |
1304 | 1305 | qemu_get_clock(vm_clock))) || |
1305 | 1306 | qemu_timer_expired(active_timers[QEMU_TIMER_REALTIME], |
1306 | 1307 | qemu_get_clock(rt_clock))) { |
1308 | + CPUState *env = next_cpu; | |
1309 | + static const char byte = 0; | |
1310 | + | |
1307 | 1311 | #ifdef _WIN32 |
1308 | 1312 | struct qemu_alarm_win32 *data = ((struct qemu_alarm_timer*)dwUser)->priv; |
1309 | 1313 | SetEvent(data->host_alarm); |
1310 | 1314 | #endif |
1311 | - CPUState *env = next_cpu; | |
1312 | 1315 | |
1316 | + write(alarm_timer_wfd, &byte, sizeof(byte)); | |
1313 | 1317 | alarm_timer->flags |= ALARM_FLAG_EXPIRED; |
1314 | 1318 | |
1315 | 1319 | if (env) { |
... | ... | @@ -1674,6 +1678,20 @@ static void init_timer_alarm(void) |
1674 | 1678 | { |
1675 | 1679 | struct qemu_alarm_timer *t = NULL; |
1676 | 1680 | int i, err = -1; |
1681 | + int fds[2]; | |
1682 | + | |
1683 | + if (pipe(fds) < 0) { | |
1684 | + fail: | |
1685 | + perror("creating timer pipe"); | |
1686 | + exit(1); | |
1687 | + } | |
1688 | + for (i = 0; i < 2; i++) { | |
1689 | + int flags = fcntl(fds[i], F_GETFL); | |
1690 | + if (flags == -1 || fcntl(fds[i], F_SETFL, flags | O_NONBLOCK)) | |
1691 | + goto fail; | |
1692 | + } | |
1693 | + alarm_timer_rfd = fds[0]; | |
1694 | + alarm_timer_wfd = fds[1]; | |
1677 | 1695 | |
1678 | 1696 | for (i = 0; alarm_timers[i].name; i++) { |
1679 | 1697 | t = &alarm_timers[i]; |
... | ... | @@ -4426,8 +4444,9 @@ void main_loop_wait(int timeout) |
4426 | 4444 | |
4427 | 4445 | /* poll any events */ |
4428 | 4446 | /* XXX: separate device handlers from system ones */ |
4429 | - nfds = -1; | |
4447 | + nfds = alarm_timer_rfd; | |
4430 | 4448 | FD_ZERO(&rfds); |
4449 | + FD_SET(alarm_timer_rfd, &rfds); | |
4431 | 4450 | FD_ZERO(&wfds); |
4432 | 4451 | FD_ZERO(&xfds); |
4433 | 4452 | for(ioh = first_io_handler; ioh != NULL; ioh = ioh->next) { |
... | ... | @@ -4501,6 +4520,11 @@ void main_loop_wait(int timeout) |
4501 | 4520 | qemu_get_clock(rt_clock)); |
4502 | 4521 | |
4503 | 4522 | if (alarm_timer->flags & ALARM_FLAG_EXPIRED) { |
4523 | + char byte; | |
4524 | + do { | |
4525 | + ret = read(alarm_timer_rfd, &byte, sizeof(byte)); | |
4526 | + } while (ret != -1 || errno != EAGAIN); | |
4527 | + | |
4504 | 4528 | alarm_timer->flags &= ~(ALARM_FLAG_EXPIRED); |
4505 | 4529 | qemu_rearm_alarm_timer(alarm_timer); |
4506 | 4530 | } | ... | ... |