|
|
96a5f8 |
From 9fd3a478a3823258516f06201fa681e07dce1781 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
|
|
|
96a5f8 |
index 3d6e2f8..18e980d 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 {
|