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 | } | ... | ... |