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

Justin M. Forbes d4cdad
From 9ca6b87b877fa46c81ce8e5b5a97dca4f522a727 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
Justin M. Forbes d4cdad
Subject: [PATCH 110/118] 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
---
Justin M. Forbes d4cdad
 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
Justin M. Forbes d4cdad
index e9ef128..0d53dce 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);
Justin M. Forbes d4cdad
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
 }
Justin M. Forbes d4cdad
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
Justin M. Forbes d4cdad
index 66b5887..5e7f68e 100644
Justin M. Forbes d4cdad
--- a/qemu-char.c
Justin M. Forbes d4cdad
+++ b/qemu-char.c
Justin M. Forbes d4cdad
@@ -507,7 +507,7 @@ static CharDriverState *qemu_chr_open_mux(CharDriverState *drv)
Justin M. Forbes d4cdad
Justin M. Forbes d4cdad
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;
Justin M. Forbes d4cdad
Justin M. Forbes d4cdad
@@ -515,9 +515,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;
Justin M. Forbes d4cdad
@@ -531,7 +536,7 @@ int send_all(int fd, const void *buf, int len1)
Justin M. Forbes d4cdad
Justin M. Forbes d4cdad
 #else
Justin M. Forbes d4cdad
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;
Justin M. Forbes d4cdad
@@ -540,8 +545,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 {
Justin M. Forbes d4cdad
@@ -556,6 +568,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;
Justin M. Forbes d4cdad
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
Justin M. Forbes d4cdad
Justin M. Forbes d4cdad
 typedef struct {
Justin M. Forbes d4cdad
@@ -567,7 +617,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
 }
Justin M. Forbes d4cdad
Justin M. Forbes d4cdad
 static int fd_chr_read_poll(void *opaque)
Justin M. Forbes d4cdad
@@ -892,7 +942,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
 }
Justin M. Forbes d4cdad
Justin M. Forbes d4cdad
 static int pty_chr_read_poll(void *opaque)
Justin M. Forbes d4cdad
@@ -2196,8 +2246,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
Justin M. Forbes d4cdad
index 9e32fac..9ea33fe 100644
Justin M. Forbes d4cdad
--- a/qemu_socket.h
Justin M. Forbes d4cdad
+++ b/qemu_socket.h
Justin M. Forbes d4cdad
@@ -37,7 +37,7 @@ int qemu_socket(int domain, int type, int protocol);
Justin M. Forbes d4cdad
 int qemu_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
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);
Justin M. Forbes d4cdad
Justin M. Forbes d4cdad
 /* New, ipv6-ready socket helper functions, see qemu-sockets.c */
Justin M. Forbes d4cdad
 int inet_listen_opts(QemuOpts *opts, int port_offset);
Justin M. Forbes d4cdad
-- 
Justin M. Forbes d4cdad
1.7.7.5
Justin M. Forbes d4cdad