Commit c96f1a48d229a6080fecce4ea20bc64cabe79e32

Authored by aliguori
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
... ... @@ -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 }
... ...