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 4/9] QContext: QEMU event loop context, abstract base class
Date: Fri,  3 May 2013 11:03:47 -0500	[thread overview]
Message-ID: <1367597032-28934-5-git-send-email-mdroth@linux.vnet.ibm.com> (raw)
In-Reply-To: <1367597032-28934-1-git-send-email-mdroth@linux.vnet.ibm.com>

This class provided interfaces and helper functions for an event loop
context modelled closely on GLib's GMainContext. It drives a number of
QSources, which are in turn modelled on GLib GSources, and driven in
very similar fashion (prepare/poll/check/dispatch interfaces). It also
provides a mechanism for creating a thread and driving itself.

QContexts are attached to the QOM composition tree via unique paths and
make use of that to provide global registration/query mechanisms.

QContexts implementations can be instantiated, referenced, and
run via the -object command-line parameter.

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 include/qcontext/qcontext.h |   76 +++++++++++++
 qcontext/qcontext.c         |  252 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 328 insertions(+)
 create mode 100644 include/qcontext/qcontext.h
 create mode 100644 qcontext/qcontext.c

diff --git a/include/qcontext/qcontext.h b/include/qcontext/qcontext.h
new file mode 100644
index 0000000..845d1a0
--- /dev/null
+++ b/include/qcontext/qcontext.h
@@ -0,0 +1,76 @@
+/*
+ * QContext: QEMU event loop context class
+ *
+ * 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 QCONTEXT_H
+#define QCONTEXT_H
+
+#include "qom/object.h"
+#include "qcontext/qsource.h"
+#include "qapi/error.h"
+#include "qemu/thread.h"
+
+/* QContext base class */
+
+typedef struct QContext QContext;
+
+typedef struct QContextClass {
+    ObjectClass parent_class;
+
+    /* called after QContext id property has been set */
+    void (*set_id_hook)(QContext *ctx, const char *name, Error **errp);
+
+    /* QContext event loop functions, abstract interfaces */
+    bool (*prepare)(QContext *ctx, int *timeout);
+    bool (*poll)(QContext *ctx, int timeout);
+    bool (*check)(QContext *ctx);
+    void (*dispatch)(QContext *ctx);
+    void (*notify)(QContext *ctx);
+
+    /* QSource registration, abstract interfaces */
+    void (*attach)(QContext *ctx, QSource *qsource, Error **errp);
+    void (*detach)(QContext *ctx, QSource *qsource, Error **errp);
+    QSource *(*find_source_by_name)(QContext *ctx, const char *name);
+} QContextClass;
+
+struct QContext {
+    Object parent_obj;
+    Object *container;
+    char *id;
+    QemuThread thread;
+    bool threaded;
+    bool should_run;
+};
+
+#define TYPE_QCONTEXT "qcontext"
+#define QCONTEXT(obj) OBJECT_CHECK(QContext, (obj), TYPE_QCONTEXT)
+#define QCONTEXT_CLASS(klass) OBJECT_CLASS_CHECK(QContextClass, (klass), TYPE_QCONTEXT)
+#define QCONTEXT_GET_CLASS(obj) OBJECT_GET_CLASS(QContextClass, (obj), TYPE_QCONTEXT)
+
+/* wrapper functions for object methods */
+
+bool qcontext_prepare(QContext *ctx, int *timeout);
+bool qcontext_poll(QContext *ctx, int timeout);
+bool qcontext_check(QContext *ctx);
+void qcontext_dispatch(QContext *ctx);
+void qcontext_notify(QContext *ctx);
+void qcontext_attach(QContext *ctx, QSource *qsource, Error **errp);
+void qcontext_detach(QContext *ctx, QSource *qsource, Error **errp);
+QSource *qcontext_find_source_by_name(QContext *ctx, const char *name);
+
+/* helper functions for working with qcontexts */
+
+QContext *qcontext_find_by_name(const char *name, Error **errp);
+bool qcontext_iterate(QContext *ctx, bool blocking);
+void qcontext_create_thread(QContext *ctx);
+void qcontext_stop_thread(QContext *ctx);
+void qcontext_register_types(void);
+
+#endif /* QCONTEXT_H */
diff --git a/qcontext/qcontext.c b/qcontext/qcontext.c
new file mode 100644
index 0000000..88cc86f
--- /dev/null
+++ b/qcontext/qcontext.c
@@ -0,0 +1,252 @@
+/*
+ * QContext: QEMU event loop context class
+ *
+ * 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 <stdio.h>
+#include "qom/object.h"
+#include "qemu/module.h"
+#include "qcontext/qcontext.h"
+#include "qapi/error.h"
+#include "string.h"
+
+/* TODO: this is for compatibility with -object, but really these
+ * should probably live in /qcontexts or something
+ */
+#define QCONTEXT_ROOT_CONTAINER "/objects"
+
+/* QContext property accessors */
+
+static char *qcontext_get_id(Object *obj, Error **errp)
+{
+    QContext *ctx = QCONTEXT(obj);
+
+    return ctx->id ? g_strdup(ctx->id) : NULL;
+}
+
+static void qcontext_set_id(Object *obj, const char *id, Error **errp)
+{
+    QContext *ctx = QCONTEXT(obj);
+    QContextClass *ctxk = QCONTEXT_GET_CLASS(ctx);
+    Object *root_container = container_get(object_get_root(),
+                                           QCONTEXT_ROOT_CONTAINER);
+
+    if (id) {
+        object_property_add_child(root_container, id, OBJECT(ctx), errp);
+        ctx->id = g_strdup(id);
+    } else {
+        ctx->id = object_property_add_unnamed_child(root_container,
+                                                    OBJECT(ctx), errp);
+    }
+
+    if (ctxk->set_id_hook) {
+        ctxk->set_id_hook(ctx, id, errp);
+    }
+}
+
+static char *qcontext_get_threaded(Object *obj, Error **errp)
+{
+    QContext *ctx = QCONTEXT(obj);
+
+    return ctx->threaded ? g_strdup("yes") : g_strdup("no");
+}
+
+static void qcontext_set_threaded(Object *obj, const char *threaded,
+                                  Error **errp)
+{
+    QContext *ctx = QCONTEXT(obj);
+
+    if (strcmp(threaded, "yes") == 0) {
+        ctx->threaded = true;
+        ctx->should_run = true;
+    } else if (strcmp(threaded, "no") == 0) {
+        ctx->threaded = false;
+        ctx->should_run = false;
+    } else {
+        error_setg(errp,
+                   "invalid value for \"threaded\","
+                   " must specify \"yes\" or \"no\"");
+    }
+}
+
+/* QOM interfaces */
+
+static void qcontext_initfn(Object *obj)
+{
+    /* note: controlling these as properties is somewhat awkward. these are
+     * really static initialization parameters, but we do it this way so we
+     * can instantiate from the command-line via -object.
+     */
+    object_property_add_str(obj, "id",
+                            qcontext_get_id,
+                            qcontext_set_id,
+                            NULL);
+    object_property_add_str(obj, "threaded",
+                            qcontext_get_threaded,
+                            qcontext_set_threaded,
+                            NULL);
+}
+
+static void qcontext_init_completionfn(Object *obj)
+{
+    QContext *ctx = QCONTEXT(obj);
+    QContextClass *ctxk = QCONTEXT_GET_CLASS(ctx);
+    gchar *path, *id;
+
+    /* this means we were created via -object, and were added to
+     * the qom tree outside of the "id" property setter. Update
+     * our internal structures to reflect this, and execute the
+     * set_id_hook() accordingly
+     */
+    if (!ctx->id) {
+        path = object_get_canonical_path(obj);
+        id = g_strrstr(path, "/") + 1;
+        ctx->id = g_strdup(id);
+        g_free(path);
+        if (ctxk->set_id_hook) {
+            ctxk->set_id_hook(ctx, ctx->id, NULL);
+        }
+    }
+
+    if (ctx->threaded) {
+        qcontext_create_thread(ctx);
+    }
+}
+
+static void qcontext_finalizefn(Object *obj)
+{
+    QContext *ctx = QCONTEXT(obj);
+
+    if (ctx->threaded) {
+        qcontext_stop_thread(ctx);
+    }
+}
+
+static void qcontext_class_initfn(ObjectClass *class, void *data)
+{
+}
+
+static const TypeInfo qcontext_type_info = {
+    .name = TYPE_QCONTEXT,
+    .parent = TYPE_OBJECT,
+    .instance_size = sizeof(QContext),
+    .instance_init = qcontext_initfn,
+    .instance_init_completion = qcontext_init_completionfn,
+    .instance_finalize = qcontext_finalizefn,
+    .class_size = sizeof(QContextClass),
+    .class_init = qcontext_class_initfn,
+    .abstract = true, /* this should be abstract, just for testing */
+};
+
+void qcontext_register_types(void)
+{
+    type_register_static(&qcontext_type_info);
+}
+
+/* FIXME: for some very strange reason, the constructor function this
+ * generates doesn't get executed for qemu. it does for test-qcontext
+ * though, and in both cases the constructor for glib-qcontext gets
+ * executed okay, so for now just do registration for qcontext there
+ * as well by making qcontext_register_types() a global and calling it
+ * from there
+ */
+//type_init(qcontext_register_types)
+
+/* QContext method wrappers. Somewhat redundant but it saves on typing */
+
+bool qcontext_prepare(QContext *ctx, int *timeout)
+{
+    return QCONTEXT_GET_CLASS(ctx)->prepare(ctx, timeout);
+}
+
+bool qcontext_poll(QContext *ctx, int timeout)
+{
+    return QCONTEXT_GET_CLASS(ctx)->poll(ctx, timeout);
+}
+
+bool qcontext_check(QContext *ctx)
+{
+    return QCONTEXT_GET_CLASS(ctx)->check(ctx);
+}
+
+void qcontext_dispatch(QContext *ctx)
+{
+    QCONTEXT_GET_CLASS(ctx)->dispatch(ctx);
+}
+
+void qcontext_notify(QContext *ctx)
+{
+    QCONTEXT_GET_CLASS(ctx)->notify(ctx);
+}
+
+void qcontext_attach(QContext *ctx, QSource *source, Error **errp)
+{
+    QCONTEXT_GET_CLASS(ctx)->attach(ctx, source, errp);
+}
+
+void qcontext_detach(QContext *ctx, QSource *source, Error **errp)
+{
+    QCONTEXT_GET_CLASS(ctx)->detach(ctx, source, errp);
+}
+
+QSource *qcontext_find_source_by_name(QContext *ctx, const char *name)
+{
+    return QCONTEXT_GET_CLASS(ctx)->find_source_by_name(ctx, name);
+}
+
+/* Helper functions for working with QContexts */
+
+QContext *qcontext_find_by_name(const char *name, Error **errp)
+{
+    char path[256];
+
+    sprintf(path, "%s/%s", QCONTEXT_ROOT_CONTAINER, name);
+    return QCONTEXT(object_resolve_path_type(path, TYPE_QCONTEXT, NULL));
+}
+
+bool qcontext_iterate(QContext *ctx, bool blocking)
+{
+    int timeout = 0; 
+
+    if (qcontext_prepare(ctx, &timeout)) {
+        qcontext_dispatch(ctx);
+        return true;
+    }
+
+    if (qcontext_poll(ctx, blocking ? timeout : 0) &&
+        qcontext_check(ctx)) {
+        qcontext_dispatch(ctx);
+        return true;
+    }
+
+    return false;
+}
+
+static void *qcontext_thread_fn(void *opaque)
+{
+    QContext *ctx = opaque;
+    while (ctx->should_run) {
+        qcontext_iterate(ctx, true);
+    }
+    return NULL;
+}
+
+void qcontext_create_thread(QContext *ctx)
+{
+    qemu_thread_create(&ctx->thread, qcontext_thread_fn,
+                       ctx, QEMU_THREAD_JOINABLE);
+}
+
+void qcontext_stop_thread(QContext *ctx)
+{
+    ctx->should_run = false;
+    qcontext_notify(ctx);
+    qemu_thread_join(&ctx->thread);
+    ctx->threaded = false;
+}
-- 
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 ` Michael Roth [this message]
2013-05-03 16:03 ` [Qemu-devel] [PATCH 5/9] GlibQContext: a QContext wrapper around GMainContexts Michael Roth
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-5-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.