[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 4/9] QContext: QEMU event loop context, abstract bas
From: |
Michael Roth |
Subject: |
[Qemu-devel] [PATCH 4/9] QContext: QEMU event loop context, abstract base class |
Date: |
Fri, 3 May 2013 11:03:47 -0500 |
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 <address@hidden>
---
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 <address@hidden>
+ *
+ * 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 <address@hidden>
+ *
+ * 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
- [Qemu-devel] [RFC 0/9] QContext: QOM class to support multiple event loops, Michael Roth, 2013/05/03
- [Qemu-devel] [PATCH 1/9] qom: add qom_init_completion, Michael Roth, 2013/05/03
- [Qemu-devel] [PATCH 3/9] QSource: QEMU event source object, Michael Roth, 2013/05/03
- [Qemu-devel] [PATCH 5/9] GlibQContext: a QContext wrapper around GMainContexts, Michael Roth, 2013/05/03
- [Qemu-devel] [PATCH 4/9] QContext: QEMU event loop context, abstract base class,
Michael Roth <=
- [Qemu-devel] [PATCH 6/9] QContext: add unit tests, Michael Roth, 2013/05/03
- [Qemu-devel] [PATCH 8/9] main-loop: drive main event loop via QContext, Michael Roth, 2013/05/03
- [Qemu-devel] [PATCH 7/9] iohandler: associate with main event loop via a QSource, Michael Roth, 2013/05/03
- [Qemu-devel] [PATCH 9/9] dataplane: use a QContext event loop in place of custom thread, Michael Roth, 2013/05/03
- Re: [Qemu-devel] [RFC 0/9] QContext: QOM class to support multiple event loops, liu ping fan, 2013/05/05