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

Hans de Goede 329b58
From 6a36990b303dc64709931e16783e2f2e0a54b9d6 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
Hans de Goede 329b58
Subject: [PATCH 105/114] char: Update send_all() to handle nonblocking
Justin M. Forbes d4cdad
 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>
Justin M. Forbes d4cdad
---
Hans de Goede 329b58
 net/socket.c  |    4 ++--
Justin M. Forbes d4cdad
 qemu-char.c   |   69 ++++++++++++++++++++++++++++++++++++++++++++++++++++-----
Justin M. Forbes d4cdad
 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
Hans de Goede 329b58
index 0bcf229..c21bb60 100644
Justin M. Forbes d4cdad
--- a/net/socket.c
Justin M. Forbes d4cdad
+++ b/net/socket.c
Justin M. Forbes d4cdad
@@ -56,8 +56,8 @@ static ssize_t net_socket_receive(VLANClientState *nc, const uint8_t *buf, size_
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
 
Justin M. Forbes d4cdad
 static ssize_t net_socket_receive_dgram(VLANClientState *nc, const uint8_t *buf, size_t size)
Justin M. Forbes d4cdad
diff --git a/qemu-char.c b/qemu-char.c
Hans de Goede 329b58
index 88cbbd0..d8059ff 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)
Hans de Goede 329b58
@@ -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 {
Justin M. Forbes d4cdad
         /* XXX: indicate an error ? */
Justin M. Forbes d4cdad
         return len;
Justin M. Forbes d4cdad
diff --git a/qemu_socket.h b/qemu_socket.h
Hans de Goede 329b58
index 4689ff3..3d780ce 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
-- 
Hans de Goede 329b58
1.7.10.4
Justin M. Forbes d4cdad