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,6 +885,7 @@ static void qemu_rearm_alarm_timer(struct qemu_alarm_timer *t)
885 #define MIN_TIMER_REARM_US 250 885 #define MIN_TIMER_REARM_US 250
886 886
887 static struct qemu_alarm_timer *alarm_timer; 887 static struct qemu_alarm_timer *alarm_timer;
  888 +static int alarm_timer_rfd, alarm_timer_wfd;
888 889
889 #ifdef _WIN32 890 #ifdef _WIN32
890 891
@@ -1304,12 +1305,15 @@ static void host_alarm_handler(int host_signum) @@ -1304,12 +1305,15 @@ static void host_alarm_handler(int host_signum)
1304 qemu_get_clock(vm_clock))) || 1305 qemu_get_clock(vm_clock))) ||
1305 qemu_timer_expired(active_timers[QEMU_TIMER_REALTIME], 1306 qemu_timer_expired(active_timers[QEMU_TIMER_REALTIME],
1306 qemu_get_clock(rt_clock))) { 1307 qemu_get_clock(rt_clock))) {
  1308 + CPUState *env = next_cpu;
  1309 + static const char byte = 0;
  1310 +
1307 #ifdef _WIN32 1311 #ifdef _WIN32
1308 struct qemu_alarm_win32 *data = ((struct qemu_alarm_timer*)dwUser)->priv; 1312 struct qemu_alarm_win32 *data = ((struct qemu_alarm_timer*)dwUser)->priv;
1309 SetEvent(data->host_alarm); 1313 SetEvent(data->host_alarm);
1310 #endif 1314 #endif
1311 - CPUState *env = next_cpu;  
1312 1315
  1316 + write(alarm_timer_wfd, &byte, sizeof(byte));
1313 alarm_timer->flags |= ALARM_FLAG_EXPIRED; 1317 alarm_timer->flags |= ALARM_FLAG_EXPIRED;
1314 1318
1315 if (env) { 1319 if (env) {
@@ -1674,6 +1678,20 @@ static void init_timer_alarm(void) @@ -1674,6 +1678,20 @@ static void init_timer_alarm(void)
1674 { 1678 {
1675 struct qemu_alarm_timer *t = NULL; 1679 struct qemu_alarm_timer *t = NULL;
1676 int i, err = -1; 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 for (i = 0; alarm_timers[i].name; i++) { 1696 for (i = 0; alarm_timers[i].name; i++) {
1679 t = &alarm_timers[i]; 1697 t = &alarm_timers[i];
@@ -4426,8 +4444,9 @@ void main_loop_wait(int timeout) @@ -4426,8 +4444,9 @@ void main_loop_wait(int timeout)
4426 4444
4427 /* poll any events */ 4445 /* poll any events */
4428 /* XXX: separate device handlers from system ones */ 4446 /* XXX: separate device handlers from system ones */
4429 - nfds = -1; 4447 + nfds = alarm_timer_rfd;
4430 FD_ZERO(&rfds); 4448 FD_ZERO(&rfds);
  4449 + FD_SET(alarm_timer_rfd, &rfds);
4431 FD_ZERO(&wfds); 4450 FD_ZERO(&wfds);
4432 FD_ZERO(&xfds); 4451 FD_ZERO(&xfds);
4433 for(ioh = first_io_handler; ioh != NULL; ioh = ioh->next) { 4452 for(ioh = first_io_handler; ioh != NULL; ioh = ioh->next) {
@@ -4501,6 +4520,11 @@ void main_loop_wait(int timeout) @@ -4501,6 +4520,11 @@ void main_loop_wait(int timeout)
4501 qemu_get_clock(rt_clock)); 4520 qemu_get_clock(rt_clock));
4502 4521
4503 if (alarm_timer->flags & ALARM_FLAG_EXPIRED) { 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 alarm_timer->flags &= ~(ALARM_FLAG_EXPIRED); 4528 alarm_timer->flags &= ~(ALARM_FLAG_EXPIRED);
4505 qemu_rearm_alarm_timer(alarm_timer); 4529 qemu_rearm_alarm_timer(alarm_timer);
4506 } 4530 }