All of lore.kernel.org
 help / color / mirror / Atom feed
From: Michael Roth <mdroth@linux.vnet.ibm.com>
To: qemu-devel@nongnu.org
Cc: pbonzini@redhat.com, aliguori@us.ibm.com, qemulist@gmail.com,
	stefanha@redhat.com
Subject: [Qemu-devel] [PATCH 5/9] GlibQContext: a QContext wrapper around GMainContexts
Date: Fri,  3 May 2013 11:03:48 -0500	[thread overview]
Message-ID: <1367597032-28934-6-git-send-email-mdroth@linux.vnet.ibm.com> (raw)
In-Reply-To: <1367597032-28934-1-git-send-email-mdroth@linux.vnet.ibm.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 <mdroth@linux.vnet.ibm.com>
---
 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      <mdroth@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 GLIB_QCONTEXT_H
+#define GLIB_QCONTEXT_H
+
+#include <glib.h>
+#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 {
+    /* <private */
+    QContext parent;
+
+    char *test;
+    GMainContext *g_main_context;
+    int max_priority;
+    GPollFD poll_fds[GLIB_QCONTEXT_MAX_POLL_FDS];
+    gint n_poll_fds;
+    QTAILQ_HEAD(, GlibQSource) sources;
+
+    /* <public> */
+} 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      <mdroth@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 <string.h>
+#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

  parent reply	other threads:[~2013-05-03 16:05 UTC|newest]

Thread overview: 28+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-05-03 16:03 [Qemu-devel] [RFC 0/9] QContext: QOM class to support multiple event loops Michael Roth
2013-05-03 16:03 ` [Qemu-devel] [PATCH 1/9] qom: add qom_init_completion Michael Roth
2013-05-06  7:45   ` Paolo Bonzini
2013-05-06 19:01     ` mdroth
2013-05-03 16:03 ` [Qemu-devel] [PATCH 2/9] qom: add object_property_add_unnamed_child Michael Roth
2013-05-06  7:44   ` Paolo Bonzini
2013-05-06 18:48     ` mdroth
2013-05-08 11:33       ` Stefan Hajnoczi
2013-05-03 16:03 ` [Qemu-devel] [PATCH 3/9] QSource: QEMU event source object Michael Roth
2013-05-03 16:03 ` [Qemu-devel] [PATCH 4/9] QContext: QEMU event loop context, abstract base class Michael Roth
2013-05-03 16:03 ` Michael Roth [this message]
2013-05-03 16:03 ` [Qemu-devel] [PATCH 6/9] QContext: add unit tests Michael Roth
2013-05-03 16:03 ` [Qemu-devel] [PATCH 7/9] iohandler: associate with main event loop via a QSource Michael Roth
2013-05-06  7:53   ` Paolo Bonzini
2013-05-06 19:03     ` mdroth
2013-08-15  6:07     ` Wenchao Xia
2013-05-03 16:03 ` [Qemu-devel] [PATCH 8/9] main-loop: drive main event loop via QContext Michael Roth
2013-05-03 16:03 ` [Qemu-devel] [PATCH 9/9] dataplane: use a QContext event loop in place of custom thread Michael Roth
2013-05-06  7:54   ` Paolo Bonzini
2013-05-06 19:13     ` mdroth
2013-05-06  3:26 ` [Qemu-devel] [RFC 0/9] QContext: QOM class to support multiple event loops liu ping fan
2013-05-06 18:43   ` mdroth
2013-05-06  7:54 ` Paolo Bonzini
2013-05-06 12:25   ` Anthony Liguori
2013-05-06 18:35     ` mdroth
2013-05-06 20:04       ` Paolo Bonzini
2013-05-06 18:17   ` mdroth
2013-05-08 11:54     ` Stefan Hajnoczi

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1367597032-28934-6-git-send-email-mdroth@linux.vnet.ibm.com \
    --to=mdroth@linux.vnet.ibm.com \
    --cc=aliguori@us.ibm.com \
    --cc=pbonzini@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=qemulist@gmail.com \
    --cc=stefanha@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.