diff options
author | Marc-André Lureau <marcandre.lureau@redhat.com> | 2021-08-04 15:08:46 +0400 |
---|---|---|
committer | Marc-André Lureau <marcandre.lureau@redhat.com> | 2021-08-05 16:15:33 +0400 |
commit | bb2b058f1a4e4fe9031133f2f7876fb12b2104d7 (patch) | |
tree | a2139984924b41b971ef12e8756400d0d39f3822 /chardev | |
parent | bf7b1eab252bc56b6bbb12a8909eae738435d6ae (diff) |
chardev: fix fd_chr_add_watch() when in != out
Create child sources for the different streams, and dispatch on the
parent source with the synthesized conditions.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Diffstat (limited to 'chardev')
-rw-r--r-- | chardev/char-fd.c | 78 |
1 files changed, 77 insertions, 1 deletions
diff --git a/chardev/char-fd.c b/chardev/char-fd.c index 1cd62f2779..743d3989b4 100644 --- a/chardev/char-fd.c +++ b/chardev/char-fd.c @@ -28,6 +28,7 @@ #include "qemu/sockets.h" #include "qapi/error.h" #include "chardev/char.h" +#include "chardev/char-fe.h" #include "io/channel-file.h" #include "chardev/char-fd.h" @@ -80,10 +81,85 @@ static int fd_chr_read_poll(void *opaque) return s->max_size; } +typedef struct FDSource { + GSource parent; + + GIOCondition cond; +} FDSource; + +static gboolean +fd_source_prepare(GSource *source, + gint *timeout_) +{ + FDSource *src = (FDSource *)source; + + return src->cond != 0; +} + +static gboolean +fd_source_check(GSource *source) +{ + FDSource *src = (FDSource *)source; + + return src->cond != 0; +} + +static gboolean +fd_source_dispatch(GSource *source, GSourceFunc callback, + gpointer user_data) +{ + FDSource *src = (FDSource *)source; + FEWatchFunc func = (FEWatchFunc)callback; + gboolean ret = G_SOURCE_CONTINUE; + + if (src->cond) { + ret = func(NULL, src->cond, user_data); + src->cond = 0; + } + + return ret; +} + +static GSourceFuncs fd_source_funcs = { + fd_source_prepare, + fd_source_check, + fd_source_dispatch, + NULL, NULL, NULL +}; + +static GSource *fd_source_new(FDChardev *chr) +{ + return g_source_new(&fd_source_funcs, sizeof(FDSource)); +} + +static gboolean child_func(GIOChannel *source, + GIOCondition condition, + gpointer data) +{ + FDSource *parent = data; + + parent->cond |= condition; + + return G_SOURCE_CONTINUE; +} + static GSource *fd_chr_add_watch(Chardev *chr, GIOCondition cond) { FDChardev *s = FD_CHARDEV(chr); - return qio_channel_create_watch(s->ioc_out, cond); + g_autoptr(GSource) source = fd_source_new(s); + + if (s->ioc_out) { + g_autoptr(GSource) child = qio_channel_create_watch(s->ioc_out, cond & ~G_IO_IN); + g_source_set_callback(child, (GSourceFunc)child_func, source, NULL); + g_source_add_child_source(source, child); + } + if (s->ioc_in) { + g_autoptr(GSource) child = qio_channel_create_watch(s->ioc_in, cond & ~G_IO_OUT); + g_source_set_callback(child, (GSourceFunc)child_func, source, NULL); + g_source_add_child_source(source, child); + } + + return g_steal_pointer(&source); } static void fd_chr_update_read_handler(Chardev *chr) |