Blame 0005-char-Update-send_all-to-handle-nonblocking-chardev-w.patch

Justin M. Forbes fc5c27
>From a962453ed73a671f566cc94858dc21ab694cc85f Mon Sep 17 00:00:00 2001
Hans de Goede 3f1f29
From: Amit Shah <amit.shah@redhat.com>
Hans de Goede 3f1f29
Date: Mon, 21 Mar 2011 22:00:27 +0100
Justin M. Forbes fc5c27
Subject: [PATCH 05/28] char: Update send_all() to handle nonblocking chardev
Hans de Goede 3f1f29
 write requests
Hans de Goede 3f1f29
Hans de Goede 3f1f29
The send_all function is modified to return to the caller in case the
Hans de Goede 3f1f29
driver cannot handle any more data.  It returns -EAGAIN or
Hans de Goede 3f1f29
WSAEWOULDBLOCK on non-Windows and Windows platforms respectively.  This
Hans de Goede 3f1f29
is only done when the caller sets a callback function handler indicating
Hans de Goede 3f1f29
it's not interested in blocking till the driver has written out all the
Hans de Goede 3f1f29
data.
Hans de Goede 3f1f29
Hans de Goede 3f1f29
Currently there's no driver or caller that supports this.  Future
Hans de Goede 3f1f29
commits will add such capability.
Hans de Goede 3f1f29
Hans de Goede 3f1f29
Signed-off-by: Amit Shah <amit.shah@redhat.com>
Hans de Goede 3f1f29
---
Hans de Goede 3f1f29
 net/socket.c  |    4 +-
Hans de Goede 3f1f29
 qemu-char.c   |   80 ++++++++++++++++++++++++++++++++++++++++++++++++++++----
Hans de Goede 3f1f29
 qemu_socket.h |    2 +-
Hans de Goede 3f1f29
 3 files changed, 77 insertions(+), 9 deletions(-)
Hans de Goede 3f1f29
Hans de Goede 3f1f29
diff --git a/net/socket.c b/net/socket.c
Justin M. Forbes 13f703
index 11fe5f3..14706fc 100644
Hans de Goede 3f1f29
--- a/net/socket.c
Hans de Goede 3f1f29
+++ b/net/socket.c
Hans de Goede 3f1f29
@@ -56,8 +56,8 @@ static ssize_t net_socket_receive(VLANClientState *nc, const uint8_t *buf, size_
Hans de Goede 3f1f29
     uint32_t len;
Hans de Goede 3f1f29
     len = htonl(size);
Hans de Goede 3f1f29
 
Hans de Goede 3f1f29
-    send_all(s->fd, (const uint8_t *)&len, sizeof(len));
Hans de Goede 3f1f29
-    return send_all(s->fd, buf, size);
Hans de Goede 3f1f29
+    send_all(NULL, s->fd, (const uint8_t *)&len, sizeof(len));
Hans de Goede 3f1f29
+    return send_all(NULL, s->fd, buf, size);
Hans de Goede 3f1f29
 }
Hans de Goede 3f1f29
 
Hans de Goede 3f1f29
 static ssize_t net_socket_receive_dgram(VLANClientState *nc, const uint8_t *buf, size_t size)
Hans de Goede 3f1f29
diff --git a/qemu-char.c b/qemu-char.c
Justin M. Forbes 13f703
index bc07b20..5dbf063 100644
Hans de Goede 3f1f29
--- a/qemu-char.c
Hans de Goede 3f1f29
+++ b/qemu-char.c
Justin M. Forbes 5e10b1
@@ -513,7 +513,7 @@ static CharDriverState *qemu_chr_open_mux(CharDriverState *drv)
Hans de Goede 3f1f29
 
Hans de Goede 3f1f29
 
Hans de Goede 3f1f29
 #ifdef _WIN32
Hans de Goede 3f1f29
-int send_all(int fd, const void *buf, int len1)
Hans de Goede 3f1f29
+static int do_send(int fd, const void *buf, int len1, bool nonblock)
Hans de Goede 3f1f29
 {
Hans de Goede 3f1f29
     int ret, len;
Hans de Goede 3f1f29
 
Justin M. Forbes 5e10b1
@@ -521,9 +521,14 @@ int send_all(int fd, const void *buf, int len1)
Hans de Goede 3f1f29
     while (len > 0) {
Hans de Goede 3f1f29
         ret = send(fd, buf, len, 0);
Hans de Goede 3f1f29
         if (ret < 0) {
Hans de Goede 3f1f29
+            if (nonblock && len1 - len) {
Hans de Goede 3f1f29
+                return len1 - len;
Hans de Goede 3f1f29
+            }
Hans de Goede 3f1f29
             errno = WSAGetLastError();
Hans de Goede 3f1f29
             if (errno != WSAEWOULDBLOCK) {
Hans de Goede 3f1f29
                 return -1;
Hans de Goede 3f1f29
+            } else if (errno == WSAEWOULDBLOCK && nonblock) {
Hans de Goede 3f1f29
+                return WSAEWOULDBLOCK;
Hans de Goede 3f1f29
             }
Hans de Goede 3f1f29
         } else if (ret == 0) {
Hans de Goede 3f1f29
             break;
Justin M. Forbes 5e10b1
@@ -537,7 +542,7 @@ int send_all(int fd, const void *buf, int len1)
Hans de Goede 3f1f29
 
Hans de Goede 3f1f29
 #else
Hans de Goede 3f1f29
 
Hans de Goede 3f1f29
-int send_all(int fd, const void *_buf, int len1)
Hans de Goede 3f1f29
+static int do_send(int fd, const void *_buf, int len1, bool nonblock)
Hans de Goede 3f1f29
 {
Hans de Goede 3f1f29
     int ret, len;
Hans de Goede 3f1f29
     const uint8_t *buf = _buf;
Justin M. Forbes 5e10b1
@@ -546,8 +551,15 @@ int send_all(int fd, const void *_buf, int len1)
Hans de Goede 3f1f29
     while (len > 0) {
Hans de Goede 3f1f29
         ret = write(fd, buf, len);
Hans de Goede 3f1f29
         if (ret < 0) {
Hans de Goede 3f1f29
-            if (errno != EINTR && errno != EAGAIN)
Hans de Goede 3f1f29
+            if (nonblock && len1 - len) {
Hans de Goede 3f1f29
+                return len1 - len;
Hans de Goede 3f1f29
+            }
Hans de Goede 3f1f29
+            if (errno == EAGAIN && nonblock) {
Hans de Goede 3f1f29
+                return -EAGAIN;
Hans de Goede 3f1f29
+            }
Hans de Goede 3f1f29
+            if (errno != EINTR && errno != EAGAIN) {
Hans de Goede 3f1f29
                 return -1;
Hans de Goede 3f1f29
+            }
Hans de Goede 3f1f29
         } else if (ret == 0) {
Hans de Goede 3f1f29
             break;
Hans de Goede 3f1f29
         } else {
Justin M. Forbes 5e10b1
@@ -559,6 +571,55 @@ int send_all(int fd, const void *_buf, int len1)
Hans de Goede 3f1f29
 }
Hans de Goede 3f1f29
 #endif /* !_WIN32 */
Hans de Goede 3f1f29
 
Hans de Goede 3f1f29
+int send_all(CharDriverState *chr, int fd, const void *_buf, int len1)
Hans de Goede 3f1f29
+{
Hans de Goede 3f1f29
+    int ret, eagain_errno;
Hans de Goede 3f1f29
+    bool nonblock;
Hans de Goede 3f1f29
+
Hans de Goede 3f1f29
+    if (chr && chr->write_blocked) {
Hans de Goede 3f1f29
+        /*
Hans de Goede 3f1f29
+         * We don't handle this situation: the caller should not send
Hans de Goede 3f1f29
+         * us data while we're blocked.
Hans de Goede 3f1f29
+         *
Hans de Goede 3f1f29
+         * We could buffer this data here but that'll only encourage
Hans de Goede 3f1f29
+         * bad behaviour on part of the callers.
Hans de Goede 3f1f29
+         *
Hans de Goede 3f1f29
+         * Also, the data already in fd's buffers isn't easily
Hans de Goede 3f1f29
+         * migratable.  If we want full migration support, all the
Hans de Goede 3f1f29
+         * data landing here needs to be buffered and on migration,
Hans de Goede 3f1f29
+         * anything that's unsent needs to be transferred to the
Hans de Goede 3f1f29
+         * dest. machine (which again isn't a very good way of solving
Hans de Goede 3f1f29
+         * the problem, as the src may become writable just during
Hans de Goede 3f1f29
+         * migration and the reader could receive some data twice,
Hans de Goede 3f1f29
+         * essentially corrupting the data).
Hans de Goede 3f1f29
+         */
Hans de Goede 3f1f29
+        abort();
Hans de Goede 3f1f29
+    }
Hans de Goede 3f1f29
+
Hans de Goede 3f1f29
+    nonblock = false;
Hans de Goede 3f1f29
+    /*
Hans de Goede 3f1f29
+     * Ensure the char backend is able to receive and handle the
Hans de Goede 3f1f29
+     * 'write unblocked' event before we turn on nonblock support.
Hans de Goede 3f1f29
+     */
Hans de Goede 3f1f29
+    if (chr && chr->chr_enable_write_fd_handler && chr->chr_write_unblocked) {
Hans de Goede 3f1f29
+        nonblock = true;
Hans de Goede 3f1f29
+    }
Hans de Goede 3f1f29
+    ret = do_send(fd, _buf, len1, nonblock);
Hans de Goede 3f1f29
+
Hans de Goede 3f1f29
+#ifdef _WIN32
Hans de Goede 3f1f29
+    eagain_errno = WSAEWOULDBLOCK;
Hans de Goede 3f1f29
+#else
Hans de Goede 3f1f29
+    eagain_errno = -EAGAIN;
Hans de Goede 3f1f29
+#endif
Hans de Goede 3f1f29
+
Hans de Goede 3f1f29
+    if (nonblock && (ret == eagain_errno || (ret >= 0 && ret < len1))) {
Hans de Goede 3f1f29
+        /* Update fd handler to wake up when chr becomes writable */
Hans de Goede 3f1f29
+        chr->chr_enable_write_fd_handler(chr);
Hans de Goede 3f1f29
+        chr->write_blocked = true;
Hans de Goede 3f1f29
+    }
Hans de Goede 3f1f29
+    return ret;
Hans de Goede 3f1f29
+}
Hans de Goede 3f1f29
+
Hans de Goede 3f1f29
 #ifndef _WIN32
Hans de Goede 3f1f29
 
Hans de Goede 3f1f29
 typedef struct {
Justin M. Forbes 5e10b1
@@ -572,7 +633,7 @@ static int stdio_nb_clients = 0;
Hans de Goede 3f1f29
 static int fd_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
Hans de Goede 3f1f29
 {
Hans de Goede 3f1f29
     FDCharDriver *s = chr->opaque;
Hans de Goede 3f1f29
-    return send_all(s->fd_out, buf, len);
Hans de Goede 3f1f29
+    return send_all(chr, s->fd_out, buf, len);
Hans de Goede 3f1f29
 }
Hans de Goede 3f1f29
 
Hans de Goede 3f1f29
 static int fd_chr_read_poll(void *opaque)
Justin M. Forbes 5e10b1
@@ -897,7 +958,7 @@ static int pty_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
Hans de Goede 3f1f29
         pty_chr_update_read_handler(chr);
Hans de Goede 3f1f29
         return 0;
Hans de Goede 3f1f29
     }
Hans de Goede 3f1f29
-    return send_all(s->fd, buf, len);
Hans de Goede 3f1f29
+    return send_all(chr, s->fd, buf, len);
Hans de Goede 3f1f29
 }
Hans de Goede 3f1f29
 
Hans de Goede 3f1f29
 static int pty_chr_read_poll(void *opaque)
Justin M. Forbes 13f703
@@ -1979,8 +2040,15 @@ static void tcp_closed(void *opaque)
Hans de Goede 3f1f29
 static int tcp_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
Hans de Goede 3f1f29
 {
Hans de Goede 3f1f29
     TCPCharDriver *s = chr->opaque;
Hans de Goede 3f1f29
+
Hans de Goede 3f1f29
     if (s->connected) {
Hans de Goede 3f1f29
-        return send_all(s->fd, buf, len);
Hans de Goede 3f1f29
+        int ret;
Hans de Goede 3f1f29
+
Hans de Goede 3f1f29
+        ret = send_all(chr, s->fd, buf, len);
Hans de Goede 3f1f29
+        if (ret == -1 && errno == EPIPE) {
Hans de Goede 3f1f29
+            tcp_closed(chr);
Hans de Goede 3f1f29
+        }
Hans de Goede 3f1f29
+        return ret;
Hans de Goede 3f1f29
     } else {
Hans de Goede 3f1f29
         /* XXX: indicate an error ? */
Hans de Goede 3f1f29
         return len;
Hans de Goede 3f1f29
diff --git a/qemu_socket.h b/qemu_socket.h
Hans de Goede 3f1f29
index 180e4db..6f453e5 100644
Hans de Goede 3f1f29
--- a/qemu_socket.h
Hans de Goede 3f1f29
+++ b/qemu_socket.h
Hans de Goede 3f1f29
@@ -36,7 +36,7 @@ int inet_aton(const char *cp, struct in_addr *ia);
Hans de Goede 3f1f29
 int qemu_socket(int domain, int type, int protocol);
Hans de Goede 3f1f29
 int qemu_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
Hans de Goede 3f1f29
 void socket_set_nonblock(int fd);
Hans de Goede 3f1f29
-int send_all(int fd, const void *buf, int len1);
Hans de Goede 3f1f29
+int send_all(CharDriverState *chr, int fd, const void *buf, int len1);
Hans de Goede 3f1f29
 
Hans de Goede 3f1f29
 /* New, ipv6-ready socket helper functions, see qemu-sockets.c */
Hans de Goede 3f1f29
 int inet_listen_opts(QemuOpts *opts, int port_offset);
Hans de Goede 3f1f29
-- 
Hans de Goede 3f1f29
1.7.5.1
Hans de Goede 3f1f29