Handle G_IO_HUP in tcp_chr_read for tcp chardev

Since commit cdaa86a54b
("Add G_IO_HUP handler for socket chardev")
GLib limitation results in a bug on Windows host. Steps to reproduce:

Start qemu: qemu-system-i386 -qmp tcp:127.0.0.1:4444:server:nowait
Connect with telnet: telnet 127.0.0.1 4444
Try sending some data from telnet.
Expected result: answers from QEMU.
Observed result: no answers (actually tcp_chr_read is not called at all).

Due to GLib limitations it is not possible to create several watches on one
channel on Windows hosts. See bug  in GNOME bugzilla for details:
https://bugzilla.gnome.org/show_bug.cgi?id=338943

This reimplements commit cdaa86a54b
("Add G_IO_HUP handler for socket chardev") using a single watch:

Handle G_IO_HUP in tcp_chr_read instead. It is already watched by a
corresponding watch.  Remove the second watch with its handler.

Cc: Antonios Motakis <a.motakis@virtualopensystems.com>
Cc: Nikolay Nikolaev <n.nikolaev@virtualopensystems.com>
Cc: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Kirill Batuzov <batuzovk@ispras.ru>
Signed-off-by: Nikita Belov <zodiac@ispras.ru>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
This commit is contained in:
Kirill Batuzov 2014-07-01 15:52:32 +04:00 committed by Michael S. Tsirkin
parent 85d1277e66
commit 812c1057f6
2 changed files with 6 additions and 22 deletions
include/sysemu
qemu-char.c

View File

@ -84,7 +84,6 @@ struct CharDriverState {
int avail_connections;
int is_mux;
guint fd_in_tag;
guint fd_hup_tag;
QemuOpts *opts;
QTAILQ_ENTRY(CharDriverState) next;
};

View File

@ -2673,6 +2673,12 @@ static gboolean tcp_chr_read(GIOChannel *chan, GIOCondition cond, void *opaque)
uint8_t buf[READ_BUF_LEN];
int len, size;
if (cond & G_IO_HUP) {
/* connection closed */
tcp_chr_disconnect(chr);
return TRUE;
}
if (!s->connected || s->max_size <= 0) {
return TRUE;
}
@ -2724,25 +2730,6 @@ CharDriverState *qemu_chr_open_eventfd(int eventfd)
}
#endif
static gboolean tcp_chr_chan_close(GIOChannel *channel, GIOCondition cond,
void *opaque)
{
CharDriverState *chr = opaque;
if (cond != G_IO_HUP) {
return FALSE;
}
/* connection closed */
tcp_chr_disconnect(chr);
if (chr->fd_hup_tag) {
g_source_remove(chr->fd_hup_tag);
chr->fd_hup_tag = 0;
}
return TRUE;
}
static void tcp_chr_connect(void *opaque)
{
CharDriverState *chr = opaque;
@ -2752,8 +2739,6 @@ static void tcp_chr_connect(void *opaque)
if (s->chan) {
chr->fd_in_tag = io_add_watch_poll(s->chan, tcp_chr_read_poll,
tcp_chr_read, chr);
chr->fd_hup_tag = g_io_add_watch(s->chan, G_IO_HUP, tcp_chr_chan_close,
chr);
}
qemu_chr_be_generic_open(chr);
}