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

5544c1
From dd7b138971deb72c7e37c4b79665df6ff5c1130b Mon Sep 17 00:00:00 2001
Justin M. Forbes d4cdad
From: Amit Shah <amit.shah@redhat.com>
Justin M. Forbes d4cdad
Date: Mon, 21 Mar 2011 22:00:27 +0100
5544c1
Subject: [PATCH] char: Update send_all() to handle nonblocking chardev write
5544c1
 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
 qemu-char.c   | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++------
b6dd5a
 qemu_socket.h |  2 +-
5544c1
 2 files changed, 64 insertions(+), 7 deletions(-)
Justin M. Forbes d4cdad
Justin M. Forbes d4cdad
diff --git a/qemu-char.c b/qemu-char.c
5544c1
index b5266d1..b46cc97 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)
5544c1
@@ -2174,8 +2224,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 {
5544c1
         /* XXX: indicate an error ? */
5544c1
         return len;
Justin M. Forbes d4cdad
diff --git a/qemu_socket.h b/qemu_socket.h
5544c1
index 3e8aee9..a537d86 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
 
5544c1
 /* callback function for nonblocking connect
5544c1
  * valid fd on success, negative error code on failure
Justin M. Forbes d4cdad
-- 
5544c1
1.7.12.1
Justin M. Forbes d4cdad