Patchwork [04/11] main-loop: switch to g_poll() on POSIX hosts

login
register
mail settings
Submitter Stefan Hajnoczi
Date Jan. 31, 2013, 10:53 a.m.
Message ID <1359629644-21920-5-git-send-email-stefanha@redhat.com>
Download mbox | patch
Permalink /patch/217163/
State New
Headers show

Comments

Stefan Hajnoczi - Jan. 31, 2013, 10:53 a.m.
Use g_poll(3) instead of select(2).  Well, this is kind of a cheat.
It's true that we're now using g_poll(3) on POSIX hosts but the *_fill()
and *_poll() functions are still using rfds/wfds/xfds.

We've set the scene to start converting *_fill() and *_poll() functions
step-by-step until no more rfds/wfds/xfds users remain.  Then we'll drop
poller_from_select() and poller_to_select() completely and be left with
native g_poll(2).

On Windows things are a little crazy: convert from rfds/wfds/xfds to
Poller, back to rfds/wfds/xfds, call select(2), rfds/wfds/xfds back to
Poller, and finally back to rfds/wfds/xfds again.  This is only
temporary and keeps the Windows build working through the following
patches.  We'll drop this excessive conversion later and be left with a
single Poller -> select(2) -> Poller sequence that allows Windows to use
select(2) while the rest of QEMU only knows about Poller.

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 main-loop.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 73 insertions(+), 8 deletions(-)

Patch

diff --git a/main-loop.c b/main-loop.c
index d0d8fe4..8d552d4 100644
--- a/main-loop.c
+++ b/main-loop.c
@@ -26,6 +26,7 @@ 
 #include "qemu/timer.h"
 #include "slirp/slirp.h"
 #include "qemu/main-loop.h"
+#include "qemu/poller.h"
 #include "block/aio.h"
 
 #ifndef _WIN32
@@ -140,12 +141,65 @@  int qemu_init_main_loop(void)
     return 0;
 }
 
+static Poller poller;
 static fd_set rfds, wfds, xfds;
 static int nfds;
 static GPollFD poll_fds[1024 * 2]; /* this is probably overkill */
 static int n_poll_fds;
 static int max_priority;
 
+/* Load rfds/wfds/xfds into Poller.  Will be removed a few commits later. */
+static void poller_from_select(void)
+{
+    int fd;
+    for (fd = 0; fd <= nfds; fd++) {
+        int events = 0;
+        if (FD_ISSET(fd, &rfds)) {
+            events |= G_IO_IN | G_IO_HUP | G_IO_ERR;
+        }
+        if (FD_ISSET(fd, &wfds)) {
+            events |= G_IO_OUT | G_IO_ERR;
+        }
+        if (FD_ISSET(fd, &xfds)) {
+            events |= G_IO_PRI;
+        }
+        if (events) {
+            poller_add_fd(&poller, fd, events);
+        }
+    }
+}
+
+/* Store Poller revents into rfds/wfds/xfds.  Will be removed a few commits
+ * later.
+ */
+static void poller_to_select(int ret)
+{
+    int i;
+
+    FD_ZERO(&rfds);
+    FD_ZERO(&wfds);
+    FD_ZERO(&xfds);
+
+    if (ret <= 0) {
+        return;
+    }
+
+    for (i = 0; i < poller.nfds; i++) {
+        int fd = poller.poll_fds[i].fd;
+        int revents = poller.poll_fds[i].revents;
+
+        if (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR)) {
+            FD_SET(fd, &rfds);
+        }
+        if (revents & (G_IO_OUT | G_IO_ERR)) {
+            FD_SET(fd, &wfds);
+        }
+        if (revents & G_IO_PRI) {
+            FD_SET(fd, &xfds);
+        }
+    }
+}
+
 #ifndef _WIN32
 static void glib_select_fill(int *max_fd, fd_set *rfds, fd_set *wfds,
                              fd_set *xfds, uint32_t *cur_timeout)
@@ -212,22 +266,22 @@  static void glib_select_poll(fd_set *rfds, fd_set *wfds, fd_set *xfds,
 
 static int os_host_main_loop_wait(uint32_t timeout)
 {
-    struct timeval tv, *tvarg = NULL;
     int ret;
 
     glib_select_fill(&nfds, &rfds, &wfds, &xfds, &timeout);
 
-    if (timeout < UINT32_MAX) {
-        tvarg = &tv;
-        tv.tv_sec = timeout / 1000;
-        tv.tv_usec = (timeout % 1000) * 1000;
-    }
-
     if (timeout > 0) {
         qemu_mutex_unlock_iothread();
     }
 
-    ret = select(nfds + 1, &rfds, &wfds, &xfds, tvarg);
+    /* We'll eventually drop fd_set completely.  But for now we still have
+     * *_fill() and *_poll() functions that use rfds/wfds/xfds.
+     */
+    poller_from_select();
+
+    ret = g_poll(poller.poll_fds, poller.nfds, timeout);
+
+    poller_to_select(ret);
 
     if (timeout > 0) {
         qemu_mutex_lock_iothread();
@@ -382,12 +436,22 @@  static int os_host_main_loop_wait(uint32_t timeout)
      * improve socket latency.
      */
 
+    /* This back-and-forth between Poller and select(2) is temporary.  We'll
+     * drop it in a couple of patches, I promise :).
+     */
+    poller_from_select();
+    FD_ZERO(&rfds);
+    FD_ZERO(&wfds);
+    FD_ZERO(&xfds);
+    nfds = poller_fill(&poller, &rfds, &wfds, &xfds);
     if (nfds >= 0) {
         select_ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv0);
         if (select_ret != 0) {
             timeout = 0;
+            poller_poll(&poller, nfds, &rfds, &wfds, &xfds);
         }
     }
+    poller_to_select(select_ret || g_poll_ret);
 
     return select_ret || g_poll_ret;
 }
@@ -403,6 +467,7 @@  int main_loop_wait(int nonblocking)
     }
 
     /* poll any events */
+    poller_reset(&poller);
     /* XXX: separate device handlers from system ones */
     nfds = -1;
     FD_ZERO(&rfds);