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

6986e1
From 98984a6b82406c233819a7afa7f35d3df4c386b0 Mon Sep 17 00:00:00 2001
22d63f
From: Amit Shah <amit.shah@redhat.com>
22d63f
Date: Mon, 21 Mar 2011 22:00:27 +0100
22d63f
Subject: [PATCH] char: Update send_all() to handle nonblocking chardev write
22d63f
 requests
22d63f
22d63f
The send_all function is modified to return to the caller in case the
22d63f
driver cannot handle any more data.  It returns -EAGAIN or
22d63f
WSAEWOULDBLOCK on non-Windows and Windows platforms respectively.  This
22d63f
is only done when the caller sets a callback function handler indicating
22d63f
it's not interested in blocking till the driver has written out all the
22d63f
data.
22d63f
22d63f
Currently there's no driver or caller that supports this.  Future
22d63f
commits will add such capability.
22d63f
22d63f
Signed-off-by: Amit Shah <amit.shah@redhat.com>
22d63f
Signed-off-by: Cole Robinson <crobinso@redhat.com>
22d63f
---
22d63f
 qemu-char.c   | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++------
22d63f
 qemu_socket.h |  2 +-
22d63f
 2 files changed, 64 insertions(+), 7 deletions(-)
22d63f
22d63f
diff --git a/qemu-char.c b/qemu-char.c
22d63f
index c9e6e36..53803a3 100644
22d63f
--- a/qemu-char.c
22d63f
+++ b/qemu-char.c
22d63f
@@ -509,7 +509,7 @@ static CharDriverState *qemu_chr_open_mux(CharDriverState *drv)
22d63f
 
22d63f
 
22d63f
 #ifdef _WIN32
22d63f
-int send_all(int fd, const void *buf, int len1)
22d63f
+static int do_send(int fd, const void *buf, int len1, bool nonblock)
22d63f
 {
22d63f
     int ret, len;
22d63f
 
22d63f
@@ -517,9 +517,14 @@ int send_all(int fd, const void *buf, int len1)
22d63f
     while (len > 0) {
22d63f
         ret = send(fd, buf, len, 0);
22d63f
         if (ret < 0) {
22d63f
+            if (nonblock && len1 - len) {
22d63f
+                return len1 - len;
22d63f
+            }
22d63f
             errno = WSAGetLastError();
22d63f
             if (errno != WSAEWOULDBLOCK) {
22d63f
                 return -1;
22d63f
+            } else if (errno == WSAEWOULDBLOCK && nonblock) {
22d63f
+                return WSAEWOULDBLOCK;
22d63f
             }
22d63f
         } else if (ret == 0) {
22d63f
             break;
22d63f
@@ -533,7 +538,7 @@ int send_all(int fd, const void *buf, int len1)
22d63f
 
22d63f
 #else
22d63f
 
22d63f
-int send_all(int fd, const void *_buf, int len1)
22d63f
+static int do_send(int fd, const void *_buf, int len1, bool nonblock)
22d63f
 {
22d63f
     int ret, len;
22d63f
     const uint8_t *buf = _buf;
22d63f
@@ -542,8 +547,15 @@ int send_all(int fd, const void *_buf, int len1)
22d63f
     while (len > 0) {
22d63f
         ret = write(fd, buf, len);
22d63f
         if (ret < 0) {
22d63f
-            if (errno != EINTR && errno != EAGAIN)
22d63f
+            if (nonblock && len1 - len) {
22d63f
+                return len1 - len;
22d63f
+            }
22d63f
+            if (errno == EAGAIN && nonblock) {
22d63f
+                return -EAGAIN;
22d63f
+            }
22d63f
+            if (errno != EINTR && errno != EAGAIN) {
22d63f
                 return -1;
22d63f
+            }
22d63f
         } else if (ret == 0) {
22d63f
             break;
22d63f
         } else {
22d63f
@@ -558,6 +570,44 @@ int send_all(int fd, const void *_buf, int len1)
22d63f
 #define STDIO_MAX_CLIENTS 1
22d63f
 static int stdio_nb_clients;
22d63f
 
22d63f
+int send_all(CharDriverState *chr, int fd, const void *_buf, int len1)
22d63f
+{
22d63f
+    int ret, eagain_errno;
22d63f
+    bool nonblock;
22d63f
+
22d63f
+    if (chr && chr->write_blocked) {
22d63f
+        /*
22d63f
+         * The caller should not send us data while we're blocked,
22d63f
+         * but this can happen when multiple writers are woken at once,
22d63f
+         * so simply return -EAGAIN.
22d63f
+         */
22d63f
+        return -EAGAIN;
22d63f
+    }
22d63f
+
22d63f
+    nonblock = false;
22d63f
+    /*
22d63f
+     * Ensure the char backend is able to receive and handle the
22d63f
+     * 'write unblocked' event before we turn on nonblock support.
22d63f
+     */
22d63f
+    if (chr && chr->chr_enable_write_fd_handler && chr->chr_write_unblocked) {
22d63f
+        nonblock = true;
22d63f
+    }
22d63f
+    ret = do_send(fd, _buf, len1, nonblock);
22d63f
+
22d63f
+#ifdef _WIN32
22d63f
+    eagain_errno = WSAEWOULDBLOCK;
22d63f
+#else
22d63f
+    eagain_errno = -EAGAIN;
22d63f
+#endif
22d63f
+
22d63f
+    if (nonblock && (ret == eagain_errno || (ret >= 0 && ret < len1))) {
22d63f
+        /* Update fd handler to wake up when chr becomes writable */
22d63f
+        chr->chr_enable_write_fd_handler(chr);
22d63f
+        chr->write_blocked = true;
22d63f
+    }
22d63f
+    return ret;
22d63f
+}
22d63f
+
22d63f
 #ifndef _WIN32
22d63f
 
22d63f
 typedef struct {
22d63f
@@ -569,7 +619,7 @@ typedef struct {
22d63f
 static int fd_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
22d63f
 {
22d63f
     FDCharDriver *s = chr->opaque;
22d63f
-    return send_all(s->fd_out, buf, len);
22d63f
+    return send_all(chr, s->fd_out, buf, len);
22d63f
 }
22d63f
 
22d63f
 static int fd_chr_read_poll(void *opaque)
22d63f
@@ -888,7 +938,7 @@ static int pty_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
22d63f
         pty_chr_update_read_handler(chr);
22d63f
         return 0;
22d63f
     }
22d63f
-    return send_all(s->fd, buf, len);
22d63f
+    return send_all(chr, s->fd, buf, len);
22d63f
 }
22d63f
 
22d63f
 static int pty_chr_read_poll(void *opaque)
22d63f
@@ -2179,8 +2229,15 @@ static void tcp_closed(void *opaque)
22d63f
 static int tcp_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
22d63f
 {
22d63f
     TCPCharDriver *s = chr->opaque;
22d63f
+
22d63f
     if (s->connected) {
22d63f
-        return send_all(s->fd, buf, len);
22d63f
+        int ret;
22d63f
+
22d63f
+        ret = send_all(chr, s->fd, buf, len);
22d63f
+        if (ret == -1 && errno == EPIPE) {
22d63f
+            tcp_closed(chr);
22d63f
+        }
22d63f
+        return ret;
22d63f
     } else {
22d63f
         /* XXX: indicate an error ? */
22d63f
         return len;
22d63f
diff --git a/qemu_socket.h b/qemu_socket.h
22d63f
index 02490ad..cceab98 100644
22d63f
--- a/qemu_socket.h
22d63f
+++ b/qemu_socket.h
22d63f
@@ -36,7 +36,7 @@ int qemu_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
22d63f
 int socket_set_cork(int fd, int v);
22d63f
 void socket_set_block(int fd);
22d63f
 void socket_set_nonblock(int fd);
22d63f
-int send_all(int fd, const void *buf, int len1);
22d63f
+int send_all(CharDriverState *chr, int fd, const void *buf, int len1);
22d63f
 
22d63f
 /* callback function for nonblocking connect
22d63f
  * valid fd on success, negative error code on failure
22d63f
-- 
6986e1
1.8.1
22d63f