dcavalca / rpms / qemu

Forked from rpms/qemu 11 months ago
Clone

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

96a5f8
From 8b85c38edae20f5dddb82d7530ca33c2c64be0c4 Mon Sep 17 00:00:00 2001
96a5f8
From: Amit Shah <amit.shah@redhat.com>
96a5f8
Date: Mon, 21 Mar 2011 22:00:27 +0100
96a5f8
Subject: [PATCH] char: Update send_all() to handle nonblocking chardev write
96a5f8
 requests
96a5f8
96a5f8
The send_all function is modified to return to the caller in case the
96a5f8
driver cannot handle any more data.  It returns -EAGAIN or
96a5f8
WSAEWOULDBLOCK on non-Windows and Windows platforms respectively.  This
96a5f8
is only done when the caller sets a callback function handler indicating
96a5f8
it's not interested in blocking till the driver has written out all the
96a5f8
data.
96a5f8
96a5f8
Currently there's no driver or caller that supports this.  Future
96a5f8
commits will add such capability.
96a5f8
96a5f8
Signed-off-by: Amit Shah <amit.shah@redhat.com>
96a5f8
Signed-off-by: Cole Robinson <crobinso@redhat.com>
96a5f8
---
96a5f8
 include/qemu/sockets.h |  3 ++-
96a5f8
 qemu-char.c            | 69 +++++++++++++++++++++++++++++++++++++++++++++-----
96a5f8
 2 files changed, 65 insertions(+), 7 deletions(-)
96a5f8
96a5f8
diff --git a/include/qemu/sockets.h b/include/qemu/sockets.h
96a5f8
index 803ae17..8ee146c 100644
96a5f8
--- a/include/qemu/sockets.h
96a5f8
+++ b/include/qemu/sockets.h
96a5f8
@@ -29,6 +29,7 @@ int inet_aton(const char *cp, struct in_addr *ia);
96a5f8
 #include "qemu/option.h"
96a5f8
 #include "qapi/error.h"
96a5f8
 #include "qapi/qmp/qerror.h"
96a5f8
+#include "char/char.h"
96a5f8
 
96a5f8
 /* misc helpers */
96a5f8
 int qemu_socket(int domain, int type, int protocol);
96a5f8
@@ -36,7 +37,7 @@ int qemu_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
96a5f8
 int socket_set_cork(int fd, int v);
96a5f8
 void socket_set_block(int fd);
96a5f8
 void socket_set_nonblock(int fd);
96a5f8
-int send_all(int fd, const void *buf, int len1);
96a5f8
+int send_all(CharDriverState *chr, int fd, const void *buf, int len1);
96a5f8
 
96a5f8
 /* callback function for nonblocking connect
96a5f8
  * valid fd on success, negative error code on failure
96a5f8
diff --git a/qemu-char.c b/qemu-char.c
96a5f8
index ce2eba8..3d6e2f8 100644
96a5f8
--- a/qemu-char.c
96a5f8
+++ b/qemu-char.c
96a5f8
@@ -508,7 +508,7 @@ static CharDriverState *qemu_chr_open_mux(CharDriverState *drv)
96a5f8
 
96a5f8
 
96a5f8
 #ifdef _WIN32
96a5f8
-int send_all(int fd, const void *buf, int len1)
96a5f8
+static int do_send(int fd, const void *buf, int len1, bool nonblock)
96a5f8
 {
96a5f8
     int ret, len;
96a5f8
 
96a5f8
@@ -516,9 +516,14 @@ int send_all(int fd, const void *buf, int len1)
96a5f8
     while (len > 0) {
96a5f8
         ret = send(fd, buf, len, 0);
96a5f8
         if (ret < 0) {
96a5f8
+            if (nonblock && len1 - len) {
96a5f8
+                return len1 - len;
96a5f8
+            }
96a5f8
             errno = WSAGetLastError();
96a5f8
             if (errno != WSAEWOULDBLOCK) {
96a5f8
                 return -1;
96a5f8
+            } else if (errno == WSAEWOULDBLOCK && nonblock) {
96a5f8
+                return WSAEWOULDBLOCK;
96a5f8
             }
96a5f8
         } else if (ret == 0) {
96a5f8
             break;
96a5f8
@@ -532,7 +537,7 @@ int send_all(int fd, const void *buf, int len1)
96a5f8
 
96a5f8
 #else
96a5f8
 
96a5f8
-int send_all(int fd, const void *_buf, int len1)
96a5f8
+static int do_send(int fd, const void *_buf, int len1, bool nonblock)
96a5f8
 {
96a5f8
     int ret, len;
96a5f8
     const uint8_t *buf = _buf;
96a5f8
@@ -541,8 +546,15 @@ int send_all(int fd, const void *_buf, int len1)
96a5f8
     while (len > 0) {
96a5f8
         ret = write(fd, buf, len);
96a5f8
         if (ret < 0) {
96a5f8
-            if (errno != EINTR && errno != EAGAIN)
96a5f8
+            if (nonblock && len1 - len) {
96a5f8
+                return len1 - len;
96a5f8
+            }
96a5f8
+            if (errno == EAGAIN && nonblock) {
96a5f8
+                return -EAGAIN;
96a5f8
+            }
96a5f8
+            if (errno != EINTR && errno != EAGAIN) {
96a5f8
                 return -1;
96a5f8
+            }
96a5f8
         } else if (ret == 0) {
96a5f8
             break;
96a5f8
         } else {
96a5f8
@@ -557,6 +569,44 @@ int send_all(int fd, const void *_buf, int len1)
96a5f8
 #define STDIO_MAX_CLIENTS 1
96a5f8
 static int stdio_nb_clients;
96a5f8
 
96a5f8
+int send_all(CharDriverState *chr, int fd, const void *_buf, int len1)
96a5f8
+{
96a5f8
+    int ret, eagain_errno;
96a5f8
+    bool nonblock;
96a5f8
+
96a5f8
+    if (chr && chr->write_blocked) {
96a5f8
+        /*
96a5f8
+         * The caller should not send us data while we're blocked,
96a5f8
+         * but this can happen when multiple writers are woken at once,
96a5f8
+         * so simply return -EAGAIN.
96a5f8
+         */
96a5f8
+        return -EAGAIN;
96a5f8
+    }
96a5f8
+
96a5f8
+    nonblock = false;
96a5f8
+    /*
96a5f8
+     * Ensure the char backend is able to receive and handle the
96a5f8
+     * 'write unblocked' event before we turn on nonblock support.
96a5f8
+     */
96a5f8
+    if (chr && chr->chr_enable_write_fd_handler && chr->chr_write_unblocked) {
96a5f8
+        nonblock = true;
96a5f8
+    }
96a5f8
+    ret = do_send(fd, _buf, len1, nonblock);
96a5f8
+
96a5f8
+#ifdef _WIN32
96a5f8
+    eagain_errno = WSAEWOULDBLOCK;
96a5f8
+#else
96a5f8
+    eagain_errno = -EAGAIN;
96a5f8
+#endif
96a5f8
+
96a5f8
+    if (nonblock && (ret == eagain_errno || (ret >= 0 && ret < len1))) {
96a5f8
+        /* Update fd handler to wake up when chr becomes writable */
96a5f8
+        chr->chr_enable_write_fd_handler(chr);
96a5f8
+        chr->write_blocked = true;
96a5f8
+    }
96a5f8
+    return ret;
96a5f8
+}
96a5f8
+
96a5f8
 #ifndef _WIN32
96a5f8
 
96a5f8
 typedef struct {
96a5f8
@@ -568,7 +618,7 @@ typedef struct {
96a5f8
 static int fd_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
96a5f8
 {
96a5f8
     FDCharDriver *s = chr->opaque;
96a5f8
-    return send_all(s->fd_out, buf, len);
96a5f8
+    return send_all(chr, s->fd_out, buf, len);
96a5f8
 }
96a5f8
 
96a5f8
 static int fd_chr_read_poll(void *opaque)
96a5f8
@@ -893,7 +943,7 @@ static int pty_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
96a5f8
         pty_chr_update_read_handler(chr);
96a5f8
         return 0;
96a5f8
     }
96a5f8
-    return send_all(s->fd, buf, len);
96a5f8
+    return send_all(chr, s->fd, buf, len);
96a5f8
 }
96a5f8
 
96a5f8
 static int pty_chr_read_poll(void *opaque)
96a5f8
@@ -2188,8 +2238,15 @@ static void tcp_closed(void *opaque)
96a5f8
 static int tcp_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
96a5f8
 {
96a5f8
     TCPCharDriver *s = chr->opaque;
96a5f8
+
96a5f8
     if (s->connected) {
96a5f8
-        return send_all(s->fd, buf, len);
96a5f8
+        int ret;
96a5f8
+
96a5f8
+        ret = send_all(chr, s->fd, buf, len);
96a5f8
+        if (ret == -1 && errno == EPIPE) {
96a5f8
+            tcp_closed(chr);
96a5f8
+        }
96a5f8
+        return ret;
96a5f8
     } else {
96a5f8
         /* XXX: indicate an error ? */
96a5f8
         return len;