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

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