From patchwork Mon Jul 25 01:44:36 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Anthony Liguori X-Patchwork-Id: 106579 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [140.186.70.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id D5F00B6F7D for ; Mon, 25 Jul 2011 11:45:24 +1000 (EST) Received: from localhost ([::1]:52165 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QlAER-0003ql-EU for incoming@patchwork.ozlabs.org; Sun, 24 Jul 2011 21:45:19 -0400 Received: from eggs.gnu.org ([140.186.70.92]:42238) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QlAEA-0003iv-Ap for qemu-devel@nongnu.org; Sun, 24 Jul 2011 21:45:05 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1QlAE8-0005Rd-74 for qemu-devel@nongnu.org; Sun, 24 Jul 2011 21:45:02 -0400 Received: from e7.ny.us.ibm.com ([32.97.182.137]:60610) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QlAE7-0005RP-OV for qemu-devel@nongnu.org; Sun, 24 Jul 2011 21:45:00 -0400 Received: from d01relay03.pok.ibm.com (d01relay03.pok.ibm.com [9.56.227.235]) by e7.ny.us.ibm.com (8.14.4/8.13.1) with ESMTP id p6P1JPPN022655 for ; Sun, 24 Jul 2011 21:19:25 -0400 Received: from d01av04.pok.ibm.com (d01av04.pok.ibm.com [9.56.224.64]) by d01relay03.pok.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id p6P1ixZK158606 for ; Sun, 24 Jul 2011 21:44:59 -0400 Received: from d01av04.pok.ibm.com (loopback [127.0.0.1]) by d01av04.pok.ibm.com (8.14.4/8.13.1/NCO v10.0 AVout) with ESMTP id p6P1ixj8006930 for ; Sun, 24 Jul 2011 21:44:59 -0400 Received: from titi.austin.rr.com (sig-9-65-207-230.mts.ibm.com [9.65.207.230]) by d01av04.pok.ibm.com (8.14.4/8.13.1/NCO v10.0 AVin) with ESMTP id p6P1itKj006824; Sun, 24 Jul 2011 21:44:58 -0400 From: Anthony Liguori To: qemu-devel@nongnu.org Date: Sun, 24 Jul 2011 20:44:36 -0500 Message-Id: <1311558293-5855-5-git-send-email-aliguori@us.ibm.com> X-Mailer: git-send-email 1.7.4.1 In-Reply-To: <1311558293-5855-1-git-send-email-aliguori@us.ibm.com> References: <1311558293-5855-1-git-send-email-aliguori@us.ibm.com> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6, seldom 2.4 (older, 4) X-Received-From: 32.97.182.137 Cc: Anthony Liguori Subject: [Qemu-devel] [PATCH 04/21] qom: add Plug class X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org The Plug class is the base class for all objects. Plugs implement properties using the existing Visitor framework. This allows for very complex properties to be implemented. Plugs also implement life cycle management by containing a realized state. An object isn't fully constructed until its realized. By setting realized to false, an object can also be reset. Plug properties can be set to be read-only or read-write. A read-write property can be locked. While a read-write property is locked, it cannot be written to. The expectation is that some properties will be locked at realize time. Signed-off-by: Anthony Liguori --- include/qemu/plug-proptypes.h | 14 +++ include/qemu/plug.h | 73 +++++++++++++ qerror.c | 4 + qerror.h | 3 + qom/Makefile | 2 +- qom/plug-proptypes.c | 52 ++++++++++ qom/plug.c | 225 +++++++++++++++++++++++++++++++++++++++++ qom/string-visitor.c | 41 ++++++++ qom/string-visitor.h | 21 ++++ 9 files changed, 434 insertions(+), 1 deletions(-) create mode 100644 include/qemu/plug-proptypes.h create mode 100644 include/qemu/plug.h create mode 100644 qom/plug-proptypes.c create mode 100644 qom/plug.c create mode 100644 qom/string-visitor.c create mode 100644 qom/string-visitor.h diff --git a/include/qemu/plug-proptypes.h b/include/qemu/plug-proptypes.h new file mode 100644 index 0000000..2c7be0e --- /dev/null +++ b/include/qemu/plug-proptypes.h @@ -0,0 +1,14 @@ +#ifndef PLUG_PROPTYPES_H +#define PLUG_PROPTYPES_H + +#include "plug.h" + +typedef bool (PlugPropertyGetterBool)(Plug *plug); +typedef void (PlugPropertySetterBool)(Plug *plug, bool value); + +void plug_add_property_bool(Plug *plug, const char *name, + PlugPropertyGetterBool *getter, + PlugPropertySetterBool *setter, + int flags); + +#endif diff --git a/include/qemu/plug.h b/include/qemu/plug.h new file mode 100644 index 0000000..f6948a0 --- /dev/null +++ b/include/qemu/plug.h @@ -0,0 +1,73 @@ +#ifndef PLUG_H +#define PLUG_H + +#include "qemu/type.h" +#include "error.h" +#include "qapi/qapi-visit-core.h" + +typedef struct Plug Plug; +typedef struct PlugProperty PlugProperty; + +typedef enum PlugPropertyFlags +{ + PROP_F_NONE = 0, + PROP_F_READ = 1, + PROP_F_WRITE = 2, + PROP_F_READWRITE = (PROP_F_READ | PROP_F_WRITE), + PROP_F_LOCKED = 4, +} PlugPropertyFlags; + +struct Plug +{ + TypeInstance parent; + + /* private */ + bool realized; + PlugProperty *first_prop; +}; + +typedef struct PlugClass { + TypeClass parent_class; + + /* protected */ + void (*realize)(Plug *plug); + void (*unrealize)(Plug *plug); +} PlugClass; + +#define TYPE_PLUG "plug" +#define PLUG(obj) TYPE_CHECK(Plug, obj, TYPE_PLUG) +#define PLUG_GET_CLASS(obj) TYPE_GET_CLASS(PlugClass, obj, TYPE_PLUG) +#define PLUG_CLASS(obj) TYPE_CLASS_CHECK(PlugClass, obj, TYPE_PLUG) + +typedef void (PlugPropertyAccessor)(Plug *plug, const char *name, Visitor *v, void *opaque, Error **errp); +typedef void (PlugPropertyFinalize)(Plug *plug, const char *name, void *opaque); +typedef void (PropertyEnumerator)(Plug *plug, const char *name, const char *typename, int flags, void *opaque); + +void plug_set_property(Plug *plug, const char *name, Visitor *v, Error **errp); + +void plug_get_property(Plug *plug, const char *name, Visitor *v, Error **errp); + +void plug_add_property_full(Plug *plug, const char *name, + PlugPropertyAccessor *getter, + PlugPropertyAccessor *setter, + PlugPropertyFinalize *fini, + void *opaque, + const char *typename, int flags); + +void plug_foreach_property(Plug *plug, PropertyEnumerator *enumfn, void *opaque); + +void plug_lock_property(Plug *plug, const char *name); +void plug_unlock_property(Plug *plug, const char *name); + +void plug_lock_all_properties(Plug *plug); +void plug_unlock_all_properties(Plug *plug); + +void plug_set_realized(Plug *plug, bool realized); +bool plug_get_realized(Plug *plug); + +void plug_realize_all(Plug *plug); +void plug_unrealize_all(Plug *plug); + +#include "qemu/plug-proptypes.h" + +#endif diff --git a/qerror.c b/qerror.c index 69c1bc9..dbe119c 100644 --- a/qerror.c +++ b/qerror.c @@ -170,6 +170,10 @@ static const QErrorStringTable qerror_table[] = { .desc = "Property '%(device).%(property)' not found", }, { + .error_fmt = QERR_PROPERTY_READ_ONLY, + .desc = "Property '%(device).%(property)' is read only", + }, + { .error_fmt = QERR_PROPERTY_VALUE_BAD, .desc = "Property '%(device).%(property)' doesn't take value '%(value)'", }, diff --git a/qerror.h b/qerror.h index 8058456..eaabe6c 100644 --- a/qerror.h +++ b/qerror.h @@ -145,6 +145,9 @@ QError *qobject_to_qerror(const QObject *obj); #define QERR_PROPERTY_NOT_FOUND \ "{ 'class': 'PropertyNotFound', 'data': { 'device': %s, 'property': %s } }" +#define QERR_PROPERTY_READ_ONLY \ + "{ 'class': 'PropertyReadOnly', 'data': { 'device': %s, 'property': %s } }" + #define QERR_PROPERTY_VALUE_BAD \ "{ 'class': 'PropertyValueBad', 'data': { 'device': %s, 'property': %s, 'value': %s } }" diff --git a/qom/Makefile b/qom/Makefile index 838054f..8a438d5 100644 --- a/qom/Makefile +++ b/qom/Makefile @@ -1 +1 @@ -qom-obj-$(CONFIG_QOM) += type.o +qom-obj-$(CONFIG_QOM) += type.o string-visitor.o plug.o plug-proptypes.o diff --git a/qom/plug-proptypes.c b/qom/plug-proptypes.c new file mode 100644 index 0000000..e9152a7 --- /dev/null +++ b/qom/plug-proptypes.c @@ -0,0 +1,52 @@ +/** FIXME: move to generated code **/ + +#include "qemu/plug-proptypes.h" + +typedef struct FunctionPointer +{ + void (*getter)(void); + void (*setter)(void); +} FunctionPointer; + +static void plug_get_property__bool(Plug *plug, const char *name, Visitor *v, void *opaque, Error **errp) +{ + FunctionPointer *fp = opaque; + PlugPropertyGetterBool *getter = (PlugPropertyGetterBool *)fp->getter; + bool value; + + value = getter(plug); + visit_type_bool(v, &value, name, errp); +} + +static void plug_set_property__bool(Plug *plug, const char *name, Visitor *v, void *opaque, Error **errp) +{ + FunctionPointer *fp = opaque; + PlugPropertySetterBool *setter = (PlugPropertySetterBool *)fp->setter; + bool value = false; + Error *local_err = NULL; + + visit_type_bool(v, &value, name, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + setter(plug, value); +} + +void plug_add_property_bool(Plug *plug, const char *name, + PlugPropertyGetterBool *getter, + PlugPropertySetterBool *setter, + int flags) +{ + FunctionPointer *fp = qemu_mallocz(sizeof(*fp)); + + fp->getter = (void (*)(void))getter; + fp->setter = (void (*)(void))setter; + + plug_add_property_full(plug, name, + plug_get_property__bool, + plug_set_property__bool, + plug_del_property__fp, + fp, "bool", flags); +} diff --git a/qom/plug.c b/qom/plug.c new file mode 100644 index 0000000..4a5f2fb --- /dev/null +++ b/qom/plug.c @@ -0,0 +1,225 @@ +#include "qemu/plug.h" +#include "qerror.h" +#include "qom/string-visitor.h" + +#define MAX_NAME (128 + 1) +#define MAX_TYPENAME (32 + 1) + +struct PlugProperty +{ + char name[MAX_NAME]; + char typename[MAX_TYPENAME]; + + PlugPropertyAccessor *getter; + PlugPropertyAccessor *setter; + PlugPropertyFinalize *finalize; + void *opaque; + + int flags; + + PlugProperty *next; +}; + +void plug_add_property_full(Plug *plug, const char *name, + PlugPropertyAccessor *getter, + PlugPropertyAccessor *setter, + PlugPropertyFinalize *fini, + void *opaque, const char *typename, int flags) +{ + PlugProperty *prop = qemu_mallocz(sizeof(*prop)); + + snprintf(prop->name, sizeof(prop->name), "%s", name); + snprintf(prop->typename, sizeof(prop->typename), "%s", typename); + + prop->getter = getter; + prop->setter = setter; + prop->finalize = fini; + prop->opaque = opaque; + + prop->flags = flags; + + prop->next = plug->first_prop; + plug->first_prop = prop; +} + +static PlugProperty *plug_find_property(Plug *plug, const char *name) +{ + PlugProperty *prop; + + for (prop = plug->first_prop; prop; prop = prop->next) { + if (strcmp(prop->name, name) == 0) { + return prop; + } + } + + return NULL; +} + +void plug_set_property(Plug *plug, const char *name, Visitor *v, Error **errp) +{ + PlugProperty *prop = plug_find_property(plug, name); + + if (!prop) { + error_set(errp, QERR_PROPERTY_NOT_FOUND, type_get_id(TYPE_INSTANCE(plug)), name); + return; + } + + if (!(prop->flags & PROP_F_WRITE) || (prop->flags & PROP_F_LOCKED)) { + error_set(errp, QERR_PROPERTY_READ_ONLY, type_get_id(TYPE_INSTANCE(plug)), name); + return; + } + + prop->setter(plug, name, v, prop->opaque, errp); +} + +void plug_get_property(Plug *plug, const char *name, Visitor *v, Error **errp) +{ + PlugProperty *prop = plug_find_property(plug, name); + + if (!prop) { + error_set(errp, QERR_PROPERTY_NOT_FOUND, type_get_id(TYPE_INSTANCE(plug)), name); + printf("property not found\n"); + return; + } + + if (!(prop->flags & PROP_F_READ)) { + error_set(errp, QERR_PROPERTY_READ_ONLY, type_get_id(TYPE_INSTANCE(plug)), name); + printf("property read only\n"); + return; + } + + prop->getter(plug, name, v, prop->opaque, errp); +} + +void plug_lock_property(Plug *plug, const char *name) +{ + PlugProperty *prop = plug_find_property(plug, name); + + assert(prop != NULL); + + prop->flags |= PROP_F_LOCKED; +} + +void plug_unlock_property(Plug *plug, const char *name) +{ + PlugProperty *prop = plug_find_property(plug, name); + + assert(prop != NULL); + + prop->flags &= ~PROP_F_LOCKED; +} + +void plug_lock_all_properties(Plug *plug) +{ + PlugProperty *prop; + + for (prop = plug->first_prop; prop; prop = prop->next) { + prop->flags |= PROP_F_LOCKED; + } +} + +void plug_unlock_all_properties(Plug *plug) +{ + PlugProperty *prop; + + for (prop = plug->first_prop; prop; prop = prop->next) { + prop->flags &= ~PROP_F_LOCKED; + } +} + +void plug_foreach_property(Plug *plug, PropertyEnumerator *enumfn, void *opaque) +{ + PlugProperty *prop; + + for (prop = plug->first_prop; prop; prop = prop->next) { + enumfn(plug, prop->name, prop->typename, prop->flags, opaque); + } +} + +void plug_set_realized(Plug *plug, bool realized) +{ + PlugClass *class = PLUG_GET_CLASS(plug); + bool old_value = plug->realized; + + plug->realized = realized; + + if (plug->realized && !old_value) { + if (class->realize) { + class->realize(plug); + } + } else if (!plug->realized && old_value) { + if (class->unrealize) { + class->unrealize(plug); + } + } +} + +bool plug_get_realized(Plug *plug) +{ + return plug->realized; +} + +void plug_realize_all(Plug *plug) +{ + /* This doesn't loop infinitely because the callbacks are only called when + * the state changes. */ + plug_set_realized(plug, true); + plug_lock_all_properties(plug); +} + +void plug_unrealize_all(Plug *plug) +{ + /* This doesn't loop infinitely because the callbacks are only called when + * the state changes. */ + plug_set_realized(plug, false); + plug_unlock_all_properties(plug); +} + +static void plug_class_initfn(TypeClass *base_class) +{ + PlugClass *class = PLUG_CLASS(base_class); + + class->realize = plug_realize_all; + class->unrealize = plug_unrealize_all; +} + +static void plug_initfn(TypeInstance *inst) +{ + Plug *obj = PLUG(inst); + + plug_add_property_bool(obj, "realized", + plug_get_realized, + plug_set_realized, + PROP_F_READWRITE); +} + +static void plug_finifn(TypeInstance *inst) +{ + Plug *plug = PLUG(inst); + + while (plug->first_prop) { + PlugProperty *p = plug->first_prop; + + plug->first_prop = plug->first_prop->next; + if (p->finalize) { + p->finalize(plug, p->name, p->opaque); + } + qemu_free(p); + } +} + +static const TypeInfo plug_type_info = { + .name = TYPE_PLUG, + .instance_size = sizeof(Plug), + .class_size = sizeof(PlugClass), + .instance_init = plug_initfn, + .instance_finalize = plug_finifn, + .class_init = plug_class_initfn, +}; + +static void register_devices(void) +{ + type_register_static(&plug_type_info); +} + +device_init(register_devices); diff --git a/qom/string-visitor.c b/qom/string-visitor.c new file mode 100644 index 0000000..55297e2 --- /dev/null +++ b/qom/string-visitor.c @@ -0,0 +1,41 @@ +#include "string-visitor.h" + +static void string_input_visitor_int(Visitor *v, int64_t *obj, const char *name, Error **errp) +{ + StringInputVisitor *sv = container_of(v, StringInputVisitor, parent); + *obj = atoi(sv->value); +} + +static void string_input_visitor_str(Visitor *v, char **obj, const char *name, Error **errp) +{ + StringInputVisitor *sv = container_of(v, StringInputVisitor, parent); + *obj = qemu_strdup(sv->value); +} + +void string_input_visitor_init(StringInputVisitor *sv, const char *value) +{ + memset(sv, 0, sizeof(*sv)); + sv->parent.type_int = string_input_visitor_int; + sv->parent.type_str = string_input_visitor_str; + sv->value = value; +} + +static void string_output_visitor_int(Visitor *v, int64_t *obj, const char *name, Error **errp) +{ + StringOutputVisitor *sv = container_of(v, StringOutputVisitor, parent); + snprintf(sv->value, sizeof(sv->value), "%" PRId64, *obj); +} + +static void string_output_visitor_str(Visitor *v, char **obj, const char *name, Error **errp) +{ + StringOutputVisitor *sv = container_of(v, StringOutputVisitor, parent); + + snprintf(sv->value, sizeof(sv->value), "%s", *obj); +} + +void string_output_visitor_init(StringOutputVisitor *sv) +{ + memset(sv, 0, sizeof(*sv)); + sv->parent.type_int = string_output_visitor_int; + sv->parent.type_str = string_output_visitor_str; +} diff --git a/qom/string-visitor.h b/qom/string-visitor.h new file mode 100644 index 0000000..ddee3e5 --- /dev/null +++ b/qom/string-visitor.h @@ -0,0 +1,21 @@ +#ifndef STRING_VISITOR_H +#define STRING_VISITOR_H + +#include "qapi/qapi-visit-core.h" + +typedef struct StringInputVisitor +{ + Visitor parent; + const char *value; +} StringInputVisitor; + +typedef struct StringOutputVisitor +{ + Visitor parent; + char value[256]; +} StringOutputVisitor; + +void string_input_visitor_init(StringInputVisitor *sv, const char *value); +void string_output_visitor_init(StringOutputVisitor *sv); + +#endif