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