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>
This commit is contained in:
parent
bf7b1eab25
commit
bb2b058f1a
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user