This references QContext, which will be introduced later (and also references this). These will likely be squashed eventually, but we leave them separate for now for easier review.
This implements a QOM-based event source object which is used in much the same way as a GSource. Signed-off-by: Michael Roth <mdr...@linux.vnet.ibm.com> --- include/qcontext/qsource.h | 63 +++++++++++++++++++ qcontext/qsource.c | 143 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 206 insertions(+) create mode 100644 include/qcontext/qsource.h create mode 100644 qcontext/qsource.c diff --git a/include/qcontext/qsource.h b/include/qcontext/qsource.h new file mode 100644 index 0000000..7c6dd75 --- /dev/null +++ b/include/qcontext/qsource.h @@ -0,0 +1,63 @@ +/* + * QSource: QEMU event source class + * + * Copyright IBM Corp. 2013 + * + * Authors: + * Michael Roth <mdr...@linux.vnet.ibm.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ +#ifndef QSOURCE_H +#define QSOURCE_H + +#include "qom/object.h" +#include "qcontext/qcontext.h" + +typedef struct QSource QSource; + +typedef bool (*QSourceCB)(QSource *qsource); + +typedef struct QSourceFuncs { + bool (*prepare)(QSource *qsource, int *timeout); + bool (*check)(QSource *qsource); + bool (*dispatch)(QSource *qsource); + void (*finalize)(QSource *qsource); +} QSourceFuncs; + +typedef struct QSourceClass { + ObjectClass parent_class; + + void (*add_poll)(QSource *qsource, GPollFD *pfd); + void (*remove_poll)(QSource *qsource, GPollFD *pfd); + void (*set_source_funcs)(QSource *qsource, QSourceFuncs funcs); + QSourceCB (*get_callback_func)(QSource *qsource); + void (*set_callback_func)(QSource *qsource, QSourceCB cb); + void (*set_user_data)(QSource *qsource, void *user_data); + void *(*get_user_data)(QSource *qsource); +} QSourceClass; + +struct QSource { + /* <private */ + Object parent_obj; + + QSourceFuncs source_funcs; + QSourceCB callback_func; + GArray *poll_fds; + void *user_data; + struct QContext *ctx; + char *name; + + /* <public> */ +}; + +#define TYPE_QSOURCE "qsource" +#define QSOURCE(obj) OBJECT_CHECK(QSource, (obj), TYPE_QSOURCE) +#define QSOURCE_CLASS(klass) OBJECT_CLASS_CHECK(QSourceClass, (klass), TYPE_QSOURCE) +#define QSOURCE_GET_CLASS(obj) OBJECT_GET_CLASS(QSourceClass, (obj), TYPE_QSOURCE) + +QSource *qsource_new(QSourceFuncs source_funcs, QSourceCB cb, const char *name, + void *opaque); + +#endif /* QSOURCE_H */ diff --git a/qcontext/qsource.c b/qcontext/qsource.c new file mode 100644 index 0000000..1f3dcb5 --- /dev/null +++ b/qcontext/qsource.c @@ -0,0 +1,143 @@ +/* + * QSource: QEMU event source class + * + * Copyright IBM Corp. 2013 + * + * Authors: + * Michael Roth <mdr...@linux.vnet.ibm.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ +#include <glib.h> +#include "qom/object.h" +#include "qcontext/qcontext.h" +#include "qemu/module.h" + +/* FIXME: this basically causes us to destroy/rebuild an + * attached QSource/GSource every time we modify. What we + * should really have is an interface in the QContext for + * modifying an already attached source to avoid so much + * churn for simple action like adding poll fds to an + * source. The alternative is to require users to + * explicitly detach QSources before modifying them, but + * updating poll FDs/callbacks etc is a common operation + * for QSource/GSource callbacks so this limits functionality + * substantially + */ +static void qsource_update(QSource *qsource) +{ + QContext *ctx = qsource->ctx; + + if (ctx) { + qcontext_detach(ctx, qsource, NULL); + qcontext_attach(ctx, qsource, NULL); + } +} + +static void qsource_add_poll(QSource *qsource, GPollFD *pfd) +{ + g_array_append_val(qsource->poll_fds, pfd); + qsource_update(qsource); +} + +static void qsource_remove_poll(QSource *qsource, GPollFD *pfd) +{ + bool done = false; + + while (!done) { + done = true; + guint i; + for (i = 0; i < qsource->poll_fds->len; i++) { + if (g_array_index(qsource->poll_fds, GPollFD *, i) == pfd) { + g_array_remove_index(qsource->poll_fds, i); + /* iterate again to make sure we get them all */ + done = false; + break; + } + } + } + + qsource_update(qsource); +} + +static void qsource_set_source_funcs(QSource *qsource, QSourceFuncs funcs) +{ + qsource->source_funcs = funcs; + qsource_update(qsource); +} + +static QSourceCB qsource_get_callback_func(QSource *qsource) +{ + return qsource->callback_func; +} + +static void qsource_set_callback_func(QSource *qsource, QSourceCB callback_func) +{ + qsource->callback_func = callback_func; + qsource_update(qsource); +} + +static void qsource_set_user_data(QSource *qsource, void *user_data) +{ + qsource->user_data = user_data; + qsource_update(qsource); +} + +static void *qsource_get_user_data(QSource *qsource) +{ + return qsource->user_data; +} + +static void qsource_initfn(Object *obj) +{ + QSource *qsource = QSOURCE(obj); + qsource->poll_fds = g_array_new(FALSE, FALSE, sizeof(GPollFD)); + qsource->ctx = NULL; +} + +static void qsource_class_initfn(ObjectClass *class, void *data) +{ + QSourceClass *k = QSOURCE_CLASS(class); + + k->add_poll = qsource_add_poll; + k->remove_poll = qsource_remove_poll; + k->set_source_funcs = qsource_set_source_funcs; + k->get_callback_func = qsource_get_callback_func; + k->set_callback_func = qsource_set_callback_func; + k->get_user_data = qsource_get_user_data; + k->set_user_data = qsource_set_user_data; +} + +TypeInfo qsource_info = { + .name = TYPE_QSOURCE, + .parent = TYPE_OBJECT, + .instance_size = sizeof(QSource), + .class_size = sizeof(QSourceClass), + .instance_init = qsource_initfn, + .class_init = qsource_class_initfn, + .interfaces = (InterfaceInfo[]) { + { }, + }, +}; + +static void qsource_register_types(void) +{ + type_register_static(&qsource_info); +} + +type_init(qsource_register_types) + +QSource *qsource_new(QSourceFuncs funcs, QSourceCB cb, const char *name, void *opaque) +{ + QSource *qsource = QSOURCE(object_new(TYPE_QSOURCE)); + QSourceClass *qsourcek = QSOURCE_GET_CLASS(qsource); + + qsource->name = g_strdup(name); + + qsourcek->set_source_funcs(qsource, funcs); + qsourcek->set_callback_func(qsource, cb); + qsourcek->set_user_data(qsource, opaque); + + return qsource; +} -- 1.7.9.5