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

bd56df
From 1af0111d871f088f25e7854fe61302e1909ba4c4 Mon Sep 17 00:00:00 2001
bd56df
Message-Id: <1af0111d871f088f25e7854fe61302e1909ba4c4.1346162949.git.crobinso@redhat.com>
bd56df
In-Reply-To: <90a59d545ad6759c105b0bfcfca70f574482584f.1346162949.git.crobinso@redhat.com>
bd56df
References: <90a59d545ad6759c105b0bfcfca70f574482584f.1346162949.git.crobinso@redhat.com>
Justin M. Forbes d4cdad
From: Amit Shah <amit.shah@redhat.com>
Justin M. Forbes d4cdad
Date: Mon, 21 Mar 2011 22:00:27 +0100
bd56df
Subject: [PATCH 105/114] char: Update send_all() to handle nonblocking
bd56df
 chardev write requests
Justin M. Forbes d4cdad
Justin M. Forbes d4cdad
The send_all function is modified to return to the caller in case the
Justin M. Forbes d4cdad
driver cannot handle any more data.  It returns -EAGAIN or
Justin M. Forbes d4cdad
WSAEWOULDBLOCK on non-Windows and Windows platforms respectively.  This
Justin M. Forbes d4cdad
is only done when the caller sets a callback function handler indicating
Justin M. Forbes d4cdad
it's not interested in blocking till the driver has written out all the
Justin M. Forbes d4cdad
data.
Justin M. Forbes d4cdad
Justin M. Forbes d4cdad
Currently there's no driver or caller that supports this.  Future
Justin M. Forbes d4cdad
commits will add such capability.
Justin M. Forbes d4cdad
Justin M. Forbes d4cdad
Signed-off-by: Amit Shah <amit.shah@redhat.com>
bd56df
Signed-off-by: Cole Robinson <crobinso@redhat.com>
Justin M. Forbes d4cdad
---
b6dd5a
 net/socket.c  |  4 ++--
b6dd5a
 qemu-char.c   | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++------
b6dd5a
 qemu_socket.h |  2 +-
Justin M. Forbes d4cdad
 3 files changed, 66 insertions(+), 9 deletions(-)
Justin M. Forbes d4cdad
Justin M. Forbes d4cdad
diff --git a/net/socket.c b/net/socket.c
b6dd5a
index c172c24..aa7c99e 100644
Justin M. Forbes d4cdad
--- a/net/socket.c
Justin M. Forbes d4cdad
+++ b/net/socket.c
b6dd5a
@@ -53,8 +53,8 @@ static ssize_t net_socket_receive(NetClientState *nc, const uint8_t *buf, size_t
Justin M. Forbes d4cdad
     uint32_t len;
Justin M. Forbes d4cdad
     len = htonl(size);
Hans de Goede 329b58
 
Justin M. Forbes d4cdad
-    send_all(s->fd, (const uint8_t *)&len, sizeof(len));
Justin M. Forbes d4cdad
-    return send_all(s->fd, buf, size);
Justin M. Forbes d4cdad
+    send_all(NULL, s->fd, (const uint8_t *)&len, sizeof(len));
Justin M. Forbes d4cdad
+    return send_all(NULL, s->fd, buf, size);
Justin M. Forbes d4cdad
 }
Hans de Goede 329b58
 
b6dd5a
 static ssize_t net_socket_receive_dgram(NetClientState *nc, const uint8_t *buf, size_t size)
Justin M. Forbes d4cdad
diff --git a/qemu-char.c b/qemu-char.c
bd56df
index 2c573fb..c2a3138 100644
Justin M. Forbes d4cdad
--- a/qemu-char.c
Justin M. Forbes d4cdad
+++ b/qemu-char.c
Hans de Goede 329b58
@@ -508,7 +508,7 @@ static CharDriverState *qemu_chr_open_mux(CharDriverState *drv)
Hans de Goede 329b58
 
Hans de Goede 329b58
 
Justin M. Forbes d4cdad
 #ifdef _WIN32
Justin M. Forbes d4cdad
-int send_all(int fd, const void *buf, int len1)
Justin M. Forbes d4cdad
+static int do_send(int fd, const void *buf, int len1, bool nonblock)
Justin M. Forbes d4cdad
 {
Justin M. Forbes d4cdad
     int ret, len;
Hans de Goede 329b58
 
Hans de Goede 329b58
@@ -516,9 +516,14 @@ int send_all(int fd, const void *buf, int len1)
Justin M. Forbes d4cdad
     while (len > 0) {
Justin M. Forbes d4cdad
         ret = send(fd, buf, len, 0);
Justin M. Forbes d4cdad
         if (ret < 0) {
Justin M. Forbes d4cdad
+            if (nonblock && len1 - len) {
Justin M. Forbes d4cdad
+                return len1 - len;
Justin M. Forbes d4cdad
+            }
Justin M. Forbes d4cdad
             errno = WSAGetLastError();
Justin M. Forbes d4cdad
             if (errno != WSAEWOULDBLOCK) {
Justin M. Forbes d4cdad
                 return -1;
Justin M. Forbes d4cdad
+            } else if (errno == WSAEWOULDBLOCK && nonblock) {
Justin M. Forbes d4cdad
+                return WSAEWOULDBLOCK;
Justin M. Forbes d4cdad
             }
Justin M. Forbes d4cdad
         } else if (ret == 0) {
Justin M. Forbes d4cdad
             break;
Hans de Goede 329b58
@@ -532,7 +537,7 @@ int send_all(int fd, const void *buf, int len1)
Hans de Goede 329b58
 
Justin M. Forbes d4cdad
 #else
Hans de Goede 329b58
 
Justin M. Forbes d4cdad
-int send_all(int fd, const void *_buf, int len1)
Justin M. Forbes d4cdad
+static int do_send(int fd, const void *_buf, int len1, bool nonblock)
Justin M. Forbes d4cdad
 {
Justin M. Forbes d4cdad
     int ret, len;
Justin M. Forbes d4cdad
     const uint8_t *buf = _buf;
Hans de Goede 329b58
@@ -541,8 +546,15 @@ int send_all(int fd, const void *_buf, int len1)
Justin M. Forbes d4cdad
     while (len > 0) {
Justin M. Forbes d4cdad
         ret = write(fd, buf, len);
Justin M. Forbes d4cdad
         if (ret < 0) {
Justin M. Forbes d4cdad
-            if (errno != EINTR && errno != EAGAIN)
Justin M. Forbes d4cdad
+            if (nonblock && len1 - len) {
Justin M. Forbes d4cdad
+                return len1 - len;
Justin M. Forbes d4cdad
+            }
Justin M. Forbes d4cdad
+            if (errno == EAGAIN && nonblock) {
Justin M. Forbes d4cdad
+                return -EAGAIN;
Justin M. Forbes d4cdad
+            }
Justin M. Forbes d4cdad
+            if (errno != EINTR && errno != EAGAIN) {
Justin M. Forbes d4cdad
                 return -1;
Justin M. Forbes d4cdad
+            }
Justin M. Forbes d4cdad
         } else if (ret == 0) {
Justin M. Forbes d4cdad
             break;
Justin M. Forbes d4cdad
         } else {
Hans de Goede 329b58
@@ -557,6 +569,44 @@ int send_all(int fd, const void *_buf, int len1)
Justin M. Forbes d4cdad
 #define STDIO_MAX_CLIENTS 1
Justin M. Forbes d4cdad
 static int stdio_nb_clients;
Hans de Goede 329b58
 
Justin M. Forbes d4cdad
+int send_all(CharDriverState *chr, int fd, const void *_buf, int len1)
Justin M. Forbes d4cdad
+{
Justin M. Forbes d4cdad
+    int ret, eagain_errno;
Justin M. Forbes d4cdad
+    bool nonblock;
Justin M. Forbes d4cdad
+
Justin M. Forbes d4cdad
+    if (chr && chr->write_blocked) {
Justin M. Forbes d4cdad
+        /*
Justin M. Forbes d4cdad
+         * The caller should not send us data while we're blocked,
Justin M. Forbes d4cdad
+         * but this can happen when multiple writers are woken at once,
Justin M. Forbes d4cdad
+         * so simply return -EAGAIN.
Justin M. Forbes d4cdad
+         */
Justin M. Forbes d4cdad
+        return -EAGAIN;
Justin M. Forbes d4cdad
+    }
Justin M. Forbes d4cdad
+
Justin M. Forbes d4cdad
+    nonblock = false;
Justin M. Forbes d4cdad
+    /*
Justin M. Forbes d4cdad
+     * Ensure the char backend is able to receive and handle the
Justin M. Forbes d4cdad
+     * 'write unblocked' event before we turn on nonblock support.
Justin M. Forbes d4cdad
+     */
Justin M. Forbes d4cdad
+    if (chr && chr->chr_enable_write_fd_handler && chr->chr_write_unblocked) {
Justin M. Forbes d4cdad
+        nonblock = true;
Justin M. Forbes d4cdad
+    }
Justin M. Forbes d4cdad
+    ret = do_send(fd, _buf, len1, nonblock);
Justin M. Forbes d4cdad
+
Justin M. Forbes d4cdad
+#ifdef _WIN32
Justin M. Forbes d4cdad
+    eagain_errno = WSAEWOULDBLOCK;
Justin M. Forbes d4cdad
+#else
Justin M. Forbes d4cdad
+    eagain_errno = -EAGAIN;
Justin M. Forbes d4cdad
+#endif
Justin M. Forbes d4cdad
+
Justin M. Forbes d4cdad
+    if (nonblock && (ret == eagain_errno || (ret >= 0 && ret < len1))) {
Justin M. Forbes d4cdad
+        /* Update fd handler to wake up when chr becomes writable */
Justin M. Forbes d4cdad
+        chr->chr_enable_write_fd_handler(chr);
Justin M. Forbes d4cdad
+        chr->write_blocked = true;
Justin M. Forbes d4cdad
+    }
Justin M. Forbes d4cdad
+    return ret;
Justin M. Forbes d4cdad
+}
Justin M. Forbes d4cdad
+
Justin M. Forbes d4cdad
 #ifndef _WIN32
Hans de Goede 329b58
 
Justin M. Forbes d4cdad
 typedef struct {
Hans de Goede 329b58
@@ -568,7 +618,7 @@ typedef struct {
Justin M. Forbes d4cdad
 static int fd_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
Justin M. Forbes d4cdad
 {
Justin M. Forbes d4cdad
     FDCharDriver *s = chr->opaque;
Justin M. Forbes d4cdad
-    return send_all(s->fd_out, buf, len);
Justin M. Forbes d4cdad
+    return send_all(chr, s->fd_out, buf, len);
Justin M. Forbes d4cdad
 }
Hans de Goede 329b58
 
Justin M. Forbes d4cdad
 static int fd_chr_read_poll(void *opaque)
Hans de Goede 329b58
@@ -887,7 +937,7 @@ static int pty_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
Justin M. Forbes d4cdad
         pty_chr_update_read_handler(chr);
Justin M. Forbes d4cdad
         return 0;
Justin M. Forbes d4cdad
     }
Justin M. Forbes d4cdad
-    return send_all(s->fd, buf, len);
Justin M. Forbes d4cdad
+    return send_all(chr, s->fd, buf, len);
Justin M. Forbes d4cdad
 }
Hans de Goede 329b58
 
Justin M. Forbes d4cdad
 static int pty_chr_read_poll(void *opaque)
bd56df
@@ -2176,8 +2226,15 @@ static void tcp_closed(void *opaque)
Justin M. Forbes d4cdad
 static int tcp_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
Justin M. Forbes d4cdad
 {
Justin M. Forbes d4cdad
     TCPCharDriver *s = chr->opaque;
Justin M. Forbes d4cdad
+
Justin M. Forbes d4cdad
     if (s->connected) {
Justin M. Forbes d4cdad
-        return send_all(s->fd, buf, len);
Justin M. Forbes d4cdad
+        int ret;
Justin M. Forbes d4cdad
+
Justin M. Forbes d4cdad
+        ret = send_all(chr, s->fd, buf, len);
Justin M. Forbes d4cdad
+        if (ret == -1 && errno == EPIPE) {
Justin M. Forbes d4cdad
+            tcp_closed(chr);
Justin M. Forbes d4cdad
+        }
Justin M. Forbes d4cdad
+        return ret;
Justin M. Forbes d4cdad
     } else {
bd56df
         /* (Re-)connect for unconnected writing */
bd56df
         tcp_chr_connect(chr);
Justin M. Forbes d4cdad
diff --git a/qemu_socket.h b/qemu_socket.h
bd56df
index 30ae6af..fc58c8d 100644
Justin M. Forbes d4cdad
--- a/qemu_socket.h
Justin M. Forbes d4cdad
+++ b/qemu_socket.h
Hans de Goede 329b58
@@ -36,7 +36,7 @@ int qemu_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
Hans de Goede 329b58
 int socket_set_cork(int fd, int v);
Justin M. Forbes d4cdad
 void socket_set_block(int fd);
Justin M. Forbes d4cdad
 void socket_set_nonblock(int fd);
Justin M. Forbes d4cdad
-int send_all(int fd, const void *buf, int len1);
Justin M. Forbes d4cdad
+int send_all(CharDriverState *chr, int fd, const void *buf, int len1);
Hans de Goede 329b58
 
Justin M. Forbes d4cdad
 /* New, ipv6-ready socket helper functions, see qemu-sockets.c */
Hans de Goede 329b58
 int inet_listen_opts(QemuOpts *opts, int port_offset, Error **errp);
Justin M. Forbes d4cdad
-- 
b6dd5a
1.7.11.2
Justin M. Forbes d4cdad