Blame 0006-char-Equip-the-unix-tcp-backend-to-handle-nonblockin.patch

1c3066
From 6540bebbaa749d405df91516e1ca5a075e354628 Mon Sep 17 00:00:00 2001
96a5f8
From: Amit Shah <amit.shah@redhat.com>
96a5f8
Date: Mon, 21 Mar 2011 22:02:47 +0100
96a5f8
Subject: [PATCH] char: Equip the unix/tcp backend to handle nonblocking
96a5f8
 writes#
96a5f8
96a5f8
Now that the infrastructure is in place to return -EAGAIN to callers,
96a5f8
individual char drivers can set their update_fd_handlers() function to
96a5f8
set or remove an fd's write handler.  This handler checks if the driver
96a5f8
became writable.
96a5f8
96a5f8
A generic callback routine is used for unblocking writes and letting
96a5f8
users of chardevs know that a driver became writable again.
96a5f8
96a5f8
Signed-off-by: Amit Shah <amit.shah@redhat.com>
96a5f8
Signed-off-by: Cole Robinson <crobinso@redhat.com>
96a5f8
---
96a5f8
 qemu-char.c | 27 +++++++++++++++++++++++++++
96a5f8
 1 file changed, 27 insertions(+)
96a5f8
96a5f8
diff --git a/qemu-char.c b/qemu-char.c
1c3066
index 96fc54e..53d2c13 100644
96a5f8
--- a/qemu-char.c
96a5f8
+++ b/qemu-char.c
96a5f8
@@ -105,6 +105,19 @@
96a5f8
 static QTAILQ_HEAD(CharDriverStateHead, CharDriverState) chardevs =
96a5f8
     QTAILQ_HEAD_INITIALIZER(chardevs);
96a5f8
 
96a5f8
+/*
96a5f8
+ * Generic routine that gets called when chardev becomes writable.
96a5f8
+ * Lets chardev user know it's OK to send more data.
96a5f8
+ */
96a5f8
+static void char_write_unblocked(void *opaque)
96a5f8
+{
96a5f8
+    CharDriverState *chr = opaque;
96a5f8
+
96a5f8
+    chr->write_blocked = false;
96a5f8
+    chr->chr_disable_write_fd_handler(chr);
96a5f8
+    chr->chr_write_unblocked(chr->handler_opaque);
96a5f8
+}
96a5f8
+
96a5f8
 void qemu_chr_be_event(CharDriverState *s, int event)
96a5f8
 {
96a5f8
     /* Keep track if the char device is open */
96a5f8
@@ -126,6 +139,9 @@ static void qemu_chr_fire_open_event(void *opaque)
96a5f8
 {
96a5f8
     CharDriverState *s = opaque;
96a5f8
     qemu_chr_be_event(s, CHR_EVENT_OPENED);
96a5f8
+    if (s->write_blocked) {
96a5f8
+        char_write_unblocked(s);
96a5f8
+    }
96a5f8
     qemu_free_timer(s->open_timer);
96a5f8
     s->open_timer = NULL;
96a5f8
 }
96a5f8
@@ -2245,6 +2261,17 @@ static int tcp_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
96a5f8
         ret = send_all(chr, s->fd, buf, len);
96a5f8
         if (ret == -1 && errno == EPIPE) {
96a5f8
             tcp_closed(chr);
96a5f8
+
96a5f8
+            if (chr->chr_enable_write_fd_handler && chr->chr_write_unblocked) {
96a5f8
+                /*
96a5f8
+                 * Since we haven't written out anything, let's say
96a5f8
+                 * we're throttled.  This will prevent any output from
96a5f8
+                 * the guest getting lost if host-side chardev goes
96a5f8
+                 * down.  Unthrottle when we re-connect.
96a5f8
+                 */
96a5f8
+                chr->write_blocked = true;
96a5f8
+                return 0;
96a5f8
+            }
96a5f8
         }
96a5f8
         return ret;
96a5f8
     } else {