From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([208.118.235.92]:44546) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UYIU1-0001Ya-8D for qemu-devel@nongnu.org; Fri, 03 May 2013 12:05:19 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1UYITz-0007ee-BG for qemu-devel@nongnu.org; Fri, 03 May 2013 12:05:17 -0400 Received: from mail-vb0-x22c.google.com ([2607:f8b0:400c:c02::22c]:56489) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UYITz-0007eZ-73 for qemu-devel@nongnu.org; Fri, 03 May 2013 12:05:15 -0400 Received: by mail-vb0-f44.google.com with SMTP id e13so1480782vbg.31 for ; Fri, 03 May 2013 09:05:14 -0700 (PDT) Sender: fluxion From: Michael Roth Date: Fri, 3 May 2013 11:03:48 -0500 Message-Id: <1367597032-28934-6-git-send-email-mdroth@linux.vnet.ibm.com> In-Reply-To: <1367597032-28934-1-git-send-email-mdroth@linux.vnet.ibm.com> References: <1367597032-28934-1-git-send-email-mdroth@linux.vnet.ibm.com> Subject: [Qemu-devel] [PATCH 5/9] GlibQContext: a QContext wrapper around GMainContexts List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: pbonzini@redhat.com, aliguori@us.ibm.com, qemulist@gmail.com, stefanha@redhat.com This QContext implementation wraps a GMainContext and maps most interfaces to the obvious/corresponding GMainContext interfaces. It can be used as a near drop-in replacement for event loops based directly around GMainContexts, and provides support for direct handling of GSources (which is unique to GlibQContext, since GSources are opaque outside of GLib) This can be used as a stop-gap between GLib event loops and QContext implementations that don't rely on GLib. Most GSources can be trivially ported to QSources to decouple such event loops from GLib, though due to the use of things like GIOChannels where we can't easily take this approach, we'll likely have at least one GlibQContext event loop for the forseeable future. Signed-off-by: Michael Roth --- include/qcontext/glib-qcontext.h | 59 ++++++++ qcontext/glib-qcontext.c | 280 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 339 insertions(+) create mode 100644 include/qcontext/glib-qcontext.h create mode 100644 qcontext/glib-qcontext.c diff --git a/include/qcontext/glib-qcontext.h b/include/qcontext/glib-qcontext.h new file mode 100644 index 0000000..4c01c8a --- /dev/null +++ b/include/qcontext/glib-qcontext.h @@ -0,0 +1,59 @@ +/* + * GlibQContext: GLib-based QContext implementation + * + * Copyright IBM Corp. 2013 + * + * Authors: + * Michael Roth + * + * 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 GLIB_QCONTEXT_H +#define GLIB_QCONTEXT_H + +#include +#include "qom/object.h" +#include "qapi/error.h" +#include "qcontext/qcontext.h" + +/* QContextGlib implementation */ + +#define TYPE_GLIB_QCONTEXT "glib-qcontext" +#define GLIB_QCONTEXT(obj) \ + OBJECT_CHECK(GlibQContext, (obj), TYPE_GLIB_QCONTEXT) +#define GLIB_QCONTEXT_CLASS(klass) \ + OBJECT_CLASS_CHECK(GlibQContextClass, (klass), TYPE_GLIB_QCONTEXT) +#define GLIB_QCONTEXT_GET_CLASS(obj) \ + OBJECT_GET_CLASS(GlibQContextClass, (obj), TYPE_GLIB_QCONTEXT) + +#define GLIB_QCONTEXT_MAX_POLL_FDS (2 * 1024) + +typedef struct GlibQSource GlibQSource; + +typedef struct GlibQContext { + /* */ +} GlibQContext; + +typedef struct GlibQContextClass { + QContextClass parent; + + void (*init)(GlibQContext *gctx, const char *name, Error **errp); + void (*set_context)(GlibQContext *gctx, GMainContext *ctx); + GMainContext *(*get_context)(GlibQContext *gctx); +} GlibQContextClass; + +GlibQContext *glib_qcontext_new(const char *id, bool threaded, Error **errp); +GMainContext *glib_qcontext_get_context(GlibQContext *gctx); + +#endif /* GLIB_QCONTEXT_H */ diff --git a/qcontext/glib-qcontext.c b/qcontext/glib-qcontext.c new file mode 100644 index 0000000..bd9b245 --- /dev/null +++ b/qcontext/glib-qcontext.c @@ -0,0 +1,280 @@ +/* + * GlibQContext: GLib-based QContext implementation + * + * Copyright IBM Corp. 2013 + * + * Authors: + * Michael Roth + * + * 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 +#include +#include "qom/object.h" +#include "qcontext/qcontext.h" +#include "qcontext/glib-qcontext.h" +#include "qemu/module.h" +#include "qapi/error.h" + +struct GlibQSource { + GSource source; + guint source_id; + char *name; + QSource *qsource; + QTAILQ_ENTRY(GlibQSource) next; +}; + +static gboolean glib_qcontext_gsource_prepare(GSource *source, int *timeout) +{ + GlibQSource *gqsource = (GlibQSource *)source; + QSource *qsource = gqsource->qsource; + + return qsource->source_funcs.prepare(qsource, timeout); +} + +static gboolean glib_qcontext_gsource_check(GSource *source) +{ + GlibQSource *gqsource = (GlibQSource *)source; + QSource *qsource = gqsource->qsource; + + return qsource->source_funcs.check(qsource); +} + +static gboolean glib_qcontext_gsource_dispatch(GSource *source, GSourceFunc cb, + gpointer user_data) +{ + GlibQSource *gqsource = (GlibQSource *)source; + QSource *qsource = gqsource->qsource; + + return qsource->source_funcs.dispatch(qsource); +} + +static void glib_qcontext_gsource_finalize(GSource *source) +{ + GlibQSource *gqsource = (GlibQSource *)source; + QSource *qsource = gqsource->qsource; + + qsource->source_funcs.finalize(qsource); +} + +GSourceFuncs glib_gsource_funcs = { + glib_qcontext_gsource_prepare, + glib_qcontext_gsource_check, + glib_qcontext_gsource_dispatch, + glib_qcontext_gsource_finalize, +}; + +/* external interfaces */ + +static bool glib_qcontext_prepare(QContext *ctx, int *timeout) +{ + GlibQContext *gctx = GLIB_QCONTEXT(ctx); + gint calculated_timeout = 0; + gboolean ret = g_main_context_prepare(gctx->g_main_context, + &gctx->max_priority); + + gctx->n_poll_fds = g_main_context_query(gctx->g_main_context, + gctx->max_priority, + &calculated_timeout, + gctx->poll_fds, + GLIB_QCONTEXT_MAX_POLL_FDS); + if (timeout) { + *timeout = calculated_timeout; + } + + return ret; +} + +static bool glib_qcontext_poll(QContext *ctx, int timeout) +{ + GlibQContext *gctx = GLIB_QCONTEXT(ctx); + + return g_poll(gctx->poll_fds, gctx->n_poll_fds, timeout) > 0; +} + +static bool glib_qcontext_check(QContext *ctx) +{ + GlibQContext *gctx = GLIB_QCONTEXT(ctx); + + return g_main_context_check(gctx->g_main_context, + gctx->max_priority, + gctx->poll_fds, + gctx->n_poll_fds); +} + +static void glib_qcontext_dispatch(QContext *ctx) +{ + GlibQContext *gctx = GLIB_QCONTEXT(ctx); + g_main_context_dispatch(gctx->g_main_context); +} + +static void glib_qcontext_notify(QContext *ctx) +{ + GlibQContext *gctx = GLIB_QCONTEXT(ctx); + GlibQContextClass *gctxk = GLIB_QCONTEXT_GET_CLASS(gctx); + g_main_context_wakeup(gctxk->get_context(gctx)); +} + + +static void glib_qcontext_attach(QContext *ctx, QSource *qsource, Error **errp) +{ + GlibQContext *gctx = GLIB_QCONTEXT(ctx); + GSource *source = g_source_new(&glib_gsource_funcs, sizeof(GlibQSource)+512); + GlibQSource *gqsource = NULL, *new_gqsource = (GlibQSource *)source; + guint i; + + if (qsource->name) { + QTAILQ_FOREACH(gqsource, &gctx->sources, next) { + if (strcmp(gqsource->name, qsource->name) == 0) { + error_setg(errp, "duplicate name associated with source"); + g_source_destroy(source); + return; + } + } + } + + for (i = 0; i < qsource->poll_fds->len; i++) { + GPollFD *pfd = g_array_index(qsource->poll_fds, GPollFD *, i); + g_source_add_poll(source, pfd); + } + + new_gqsource->qsource = qsource; + new_gqsource->source_id = g_source_attach(source, gctx->g_main_context); + new_gqsource->name = g_strdup(qsource->name); + QTAILQ_INSERT_TAIL(&gctx->sources, new_gqsource, next); + qsource->ctx = ctx; +} + +static void glib_qcontext_detach(QContext *ctx, QSource *qsource, Error **errp) +{ + GlibQContext *gctx = GLIB_QCONTEXT(ctx); + GlibQSource *gqsource = NULL; + + QTAILQ_FOREACH(gqsource, &gctx->sources, next) { + if (gqsource->qsource == qsource) { + break; + } + } + + if (gqsource) { + g_free(gqsource->name); + g_source_remove(gqsource->source_id); + QTAILQ_REMOVE(&gctx->sources, gqsource, next); + } + + qsource->ctx = NULL; +} + +static QSource *glib_qcontext_find_source_by_name(QContext *ctx, const char *name) +{ + GlibQContext *gctx = GLIB_QCONTEXT(ctx); + GlibQSource *gqsource = NULL; + + QTAILQ_FOREACH(gqsource, &gctx->sources, next) { + if (strcmp(gqsource->name, name) == 0) { + break; + } + } + + return gqsource->qsource; +} + +static void glib_qcontext_set_id_hook(QContext *ctx, const char *id, + Error **errp) +{ + GlibQContext *gctx = GLIB_QCONTEXT(ctx); + + if (strcmp(id, "main") != 0) { + gctx->g_main_context = g_main_context_new(); + } +} + +/* QOM-driven interfaces */ +static void glib_qcontext_initfn(Object *obj) +{ + GlibQContext *gctx = GLIB_QCONTEXT(obj); + + /* TODO: this will be replaced with a new context if we set an ID + * property other than "main". there's no guarantee we won't attempt + * to spawn a main loop thread for this context (also done via a dynamic + * property so we can be fully instantiated via -object) before this + * happens though. This means we can accidentally execute a number of + * iterations of the default glib context (bad, since that requires + * special handling of BQL) before we switch over to the intended + * context. + * + * We seem to need a realizefn for Objects... + */ + gctx->g_main_context = g_main_context_default(); + QTAILQ_INIT(&gctx->sources); +} + +static void glib_qcontext_class_initfn(ObjectClass *class, void *data) +{ + QContextClass *ctxk = QCONTEXT_CLASS(class); + GlibQContextClass *gctxk = GLIB_QCONTEXT_CLASS(class); + + ctxk->prepare = glib_qcontext_prepare; + ctxk->poll = glib_qcontext_poll; + ctxk->check = glib_qcontext_check; + ctxk->dispatch = glib_qcontext_dispatch; + ctxk->notify = glib_qcontext_notify; + + ctxk->attach = glib_qcontext_attach; + ctxk->detach = glib_qcontext_detach; + ctxk->find_source_by_name = glib_qcontext_find_source_by_name; + ctxk->set_id_hook = glib_qcontext_set_id_hook; + + gctxk->get_context = glib_qcontext_get_context; +} + +static const TypeInfo glib_qcontext_info = { + .name = TYPE_GLIB_QCONTEXT, + .parent = TYPE_QCONTEXT, + .instance_size = sizeof(GlibQContext), + .class_size = sizeof(GlibQContextClass), + .instance_init = glib_qcontext_initfn, + .class_init = glib_qcontext_class_initfn, + .interfaces = (InterfaceInfo[]) { + { }, + }, +}; + +static void glib_qcontext_register_types(void) +{ + type_register_static(&glib_qcontext_info); +} + +type_init(glib_qcontext_register_types) +type_init(qcontext_register_types) + +GlibQContext *glib_qcontext_new(const char *id, bool threaded, Error **errp) +{ + GlibQContext *gctx = GLIB_QCONTEXT(object_new(TYPE_GLIB_QCONTEXT)); + + object_property_set_str(OBJECT(gctx), id, "id", errp); + if (error_is_set(errp)) { + object_unref(OBJECT(gctx)); + g_warning("marker 0"); + return NULL; + } + + object_property_set_str(OBJECT(gctx), + threaded ? "yes" : "no", + "threaded", errp); + if (error_is_set(errp)) { + object_unref(OBJECT(gctx)); + g_warning("marker 1"); + return NULL; + } + + object_init_completion(OBJECT(gctx)); + + return gctx; +} + +GMainContext *glib_qcontext_get_context(GlibQContext *gctx) +{ + return gctx->g_main_context; +} -- 1.7.9.5