[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH 2/3] qom: reimplement Interfaces
From: |
Peter Crosthwaite |
Subject: |
Re: [Qemu-devel] [PATCH 2/3] qom: reimplement Interfaces |
Date: |
Fri, 22 Jun 2012 21:29:01 +1000 |
Hi Anthony,
With the latest qom-next merge, this fails to rebase with non-trivial
conflicts. Do you have a rebased version of this floating around in
one of your trees somewhere? We are trying to get our machine models
as QOMified as we can, especially the axi-stream stuff. I will also be
able to put some --tested-by to this stuff with the microblaze machine
model. Let me know if/how I can help.
Regards,
Peter
On Sat, Jun 16, 2012 at 8:47 PM, Peter Crosthwaite
<address@hidden> wrote:
> On Wed, 2012-06-13 at 15:55 -0500, Anthony Liguori wrote:
>> The current implementation of Interfaces is poorly designed. Each interface
>> that an object implements end up being an object that's tracked by the
>
> "ends"
>
>> implementing object. There's all sorts of gymnastics to deal with casting
>> between these objects.
>>
>> By an interface shouldn't be associated with an Object. Interfaces are
>> global
>
> "But" ?
>
>> to a class. This patch moves all Interface knowledge to ObjectClass
>> eliminating
>> the relationship between Object and Interfaces.
>>
>> Interfaces are now abstract (as they should be) but this is okay. Interfaces
>> essentially act as additional parents for the classes and are treated as
>> such.
>>
>> With this new implementation, we should fully support derived interfaces
>> including reimplementing an inherited interface.
>>
>> Signed-off-by: Anthony Liguori <address@hidden>
>> ---
>> include/qemu/object.h | 64 +++++++++++---
>> qom/object.c | 231
>> +++++++++++++++++++++++-------------------------
>> 2 files changed, 160 insertions(+), 135 deletions(-)
>>
>> diff --git a/include/qemu/object.h b/include/qemu/object.h
>> index d93b772..72cb290 100644
>> --- a/include/qemu/object.h
>> +++ b/include/qemu/object.h
>> @@ -239,6 +239,7 @@ struct ObjectClass
>> {
>> /*< private >*/
>> Type type;
>> + GSList *interfaces;
>> };
>>
>> /**
>> @@ -260,7 +261,6 @@ struct Object
>> {
>> /*< private >*/
>> ObjectClass *class;
>> - GSList *interfaces;
>> QTAILQ_HEAD(, ObjectProperty) properties;
>> uint32_t ref;
>> Object *parent;
>> @@ -381,6 +381,17 @@ struct TypeInfo
>> OBJECT_CLASS_CHECK(class, object_get_class(OBJECT(obj)), name)
>>
>> /**
>> + * InterfaceInfo:
>> + * @type: The name of the interface.
>> + *
>> + * The information associated with an interface.
>> + */
>> +struct InterfaceInfo
>> +{
>> + const char *type;
>> +};
>> +
>> +/**
>> * InterfaceClass:
>> * @parent_class: the base class
>> *
>> @@ -390,26 +401,31 @@ struct TypeInfo
>> struct InterfaceClass
>> {
>> ObjectClass parent_class;
>> + /*< private >*/
>> + ObjectClass *concrete_class;
>> };
>>
>> +#define TYPE_INTERFACE "interface"
>> +
>> /**
>> - * InterfaceInfo:
>> - * @type: The name of the interface.
>> - * @interface_initfn: This method is called during class initialization and
>> is
>> - * used to initialize an interface associated with a class. This function
>> - * should initialize any default virtual functions for a class and/or
>> override
>> - * virtual functions in a parent class.
>> + * INTERFACE_CLASS:
>> + * @klass: class to cast from
>> *
>> - * The information associated with an interface.
>> + * Returns: An #InterfaceClass or raise an error if cast is invalid
>> */
>> -struct InterfaceInfo
>> -{
>> - const char *type;
>> +#define INTERFACE_CLASS(klass) \
>> + OBJECT_CLASS_CHECK(InterfaceClass, klass, TYPE_INTERFACE)
>>
>> - void (*interface_initfn)(ObjectClass *class, void *data);
>> -};
>> -
>> -#define TYPE_INTERFACE "interface"
>> +/**
>> + * INTERFACE_CHECK:
>> + * @interface: the type to return
>> + * @obj: the object to convert to an interface
>> + * @name: the interface type name
>> + *
>> + * Returns: @obj casted to @interface if cast is valid, otherwise raise
>> error.
>> + */
>> +#define INTERFACE_CHECK(interface, obj, name) \
>> + ((interface *)interface_dynamic_cast_assert(OBJECT((obj)), (name)))
>>
>> /**
>> * object_new:
>> @@ -548,6 +564,24 @@ ObjectClass *object_class_dynamic_cast(ObjectClass
>> *klass,
>> const char *typename);
>>
>> /**
>> + * interface_dynamic_cast_assert:
>> + * @obj: the object to cast to an interface type
>> + * @typename: the type name of the interface
>> + *
>> + * Returns: @obj if @obj implements @typename, otherwise raise an error
>> + */
>> +Object *interface_dynamic_cast_assert(Object *obj, const char *typename);
>> +
>> +/**
>> + * interface_dynamic_cast_assert:
>> + * @obj: the object to cast to an interface type
>> + * @typename: the type name of the interface
>> + *
>> + * Returns: @obj if @obj implements @typename, otherwise %NULL
>> + */
>> +Object *interface_dynamic_cast(Object *obj, const char *typename);
>> +
>
> This is where bug was introduced for links. The link setter code uses
> object_dynamic_cast() which shortcuts the logic here, that is needed for
> casting interfaces. The new result is you can use interface with links
> cos the cast pukes.
>
> I have proposed a solution to this in my new revision (P3) of the
> axi-stream series.
>
> Regards,
> Peter
>
>> +/**
>> * object_class_get_name:
>> * @klass: The class to obtain the QOM typename for.
>> *
>> diff --git a/qom/object.c b/qom/object.c
>> index 6f839ad..aa26693 100644
>> --- a/qom/object.c
>> +++ b/qom/object.c
>> @@ -31,9 +31,7 @@ typedef struct TypeImpl TypeImpl;
>>
>> struct InterfaceImpl
>> {
>> - const char *parent;
>> - void (*interface_initfn)(ObjectClass *class, void *data);
>> - TypeImpl *type;
>> + const char *typename;
>> };
>>
>> struct TypeImpl
>> @@ -63,14 +61,6 @@ struct TypeImpl
>> InterfaceImpl interfaces[MAX_INTERFACES];
>> };
>>
>> -typedef struct Interface
>> -{
>> - Object parent;
>> - Object *obj;
>> -} Interface;
>> -
>> -#define INTERFACE(obj) OBJECT_CHECK(Interface, obj, TYPE_INTERFACE)
>> -
>> static Type type_interface;
>>
>> static GHashTable *type_table_get(void)
>> @@ -97,6 +87,7 @@ static TypeImpl *type_table_lookup(const char *name)
>> TypeImpl *type_register(const TypeInfo *info)
>> {
>> TypeImpl *ti = g_malloc0(sizeof(*ti));
>> + int i;
>>
>> g_assert(info->name != NULL);
>>
>> @@ -120,15 +111,10 @@ TypeImpl *type_register(const TypeInfo *info)
>>
>> ti->abstract = info->abstract;
>>
>> - if (info->interfaces) {
>> - int i;
>> -
>> - for (i = 0; info->interfaces[i].type; i++) {
>> - ti->interfaces[i].parent = info->interfaces[i].type;
>> - ti->interfaces[i].interface_initfn =
>> info->interfaces[i].interface_initfn;
>> - ti->num_interfaces++;
>> - }
>> + for (i = 0; info->interfaces && info->interfaces[i].type; i++) {
>> + ti->interfaces[i].typename = g_strdup(info->interfaces[i].type);
>> }
>> + ti->num_interfaces = i;
>>
>> type_table_add(ti);
>>
>> @@ -190,26 +176,48 @@ static size_t type_object_get_size(TypeImpl *ti)
>> return 0;
>> }
>>
>> -static void type_class_interface_init(TypeImpl *ti, InterfaceImpl *iface)
>> +static bool type_is_ancestor(TypeImpl *type, TypeImpl *target_type)
>> {
>> - TypeInfo info = {
>> - .instance_size = sizeof(Interface),
>> - .parent = iface->parent,
>> - .class_size = sizeof(InterfaceClass),
>> - .class_init = iface->interface_initfn,
>> - .abstract = true,
>> - };
>> - char *name = g_strdup_printf("<%s::%s>", ti->name, iface->parent);
>> + assert(target_type);
>> +
>> + /* Check if typename is a direct ancestor of type */
>> + while (type) {
>> + if (type == target_type) {
>> + return true;
>> + }
>> +
>> + type = type_get_parent(type);
>> + }
>> +
>> + return false;
>> +}
>> +
>> +static void type_initialize(TypeImpl *ti);
>> +
>> +static void type_initialize_interface(TypeImpl *ti, const char *parent)
>> +{
>> + InterfaceClass *new_iface;
>> + TypeInfo info = { };
>> + TypeImpl *iface_impl;
>>
>> - info.name = name;
>> - iface->type = type_register(&info);
>> - g_free(name);
>> + info.parent = parent;
>> + info.name = g_strdup_printf("%s::%s", ti->name, info.parent);
>> + info.abstract = true;
>> +
>> + iface_impl = type_register(&info);
>> + type_initialize(iface_impl);
>> + g_free((char *)info.name);
>> +
>> + new_iface = (InterfaceClass *)iface_impl->class;
>> + new_iface->concrete_class = ti->class;
>> +
>> + ti->class->interfaces = g_slist_append(ti->class->interfaces,
>> + iface_impl->class);
>> }
>>
>> static void type_initialize(TypeImpl *ti)
>> {
>> size_t class_size = sizeof(ObjectClass);
>> - int i;
>>
>> if (ti->class) {
>> return;
>> @@ -221,8 +229,12 @@ static void type_initialize(TypeImpl *ti)
>> ti->class = g_malloc0(ti->class_size);
>> ti->class->type = ti;
>>
>> + ti->class->interfaces = NULL;
>> +
>> if (type_has_parent(ti)) {
>> TypeImpl *parent = type_get_parent(ti);
>> + GSList *e;
>> + int i;
>>
>> type_initialize(parent);
>>
>> @@ -232,42 +244,46 @@ static void type_initialize(TypeImpl *ti)
>> memcpy((void *)ti->class + sizeof(ObjectClass),
>> (void *)parent->class + sizeof(ObjectClass),
>> parent->class_size - sizeof(ObjectClass));
>> - }
>>
>> - memset((void *)ti->class + class_size, 0, ti->class_size - class_size);
>> + for (e = parent->class->interfaces; e; e = e->next) {
>> + ObjectClass *iface = e->data;
>> + type_initialize_interface(ti, object_class_get_name(iface));
>> + }
>>
>> - for (i = 0; i < ti->num_interfaces; i++) {
>> - type_class_interface_init(ti, &ti->interfaces[i]);
>> - }
>> + for (i = 0; i < ti->num_interfaces; i++) {
>> + TypeImpl *t = type_get_by_name(ti->interfaces[i].typename);
>>
>> - if (ti->class_init) {
>> - ti->class_init(ti->class, ti->class_data);
>> + for (e = ti->class->interfaces; e; e = e->next) {
>> + TypeImpl *target_type = OBJECT_CLASS(e->data)->type;
>> +
>> + if (type_is_ancestor(target_type, t)) {
>> + break;
>> + }
>> + }
>> +
>> + if (e) {
>> + continue;
>> + }
>> +
>> + type_initialize_interface(ti, ti->interfaces[i].typename);
>> + }
>> }
>> -}
>>
>> -static void object_interface_init(Object *obj, InterfaceImpl *iface)
>> -{
>> - TypeImpl *ti = iface->type;
>> - Interface *iface_obj;
>> + /* If this type is an interface and num_interfaces, bugger out */
>>
>> - iface_obj = INTERFACE(object_new(ti->name));
>> - iface_obj->obj = obj;
>> + memset((void *)ti->class + class_size, 0, ti->class_size - class_size);
>>
>> - obj->interfaces = g_slist_prepend(obj->interfaces, iface_obj);
>> + if (ti->class_init) {
>> + ti->class_init(ti->class, ti->class_data);
>> + }
>> }
>>
>> static void object_init_with_type(Object *obj, TypeImpl *ti)
>> {
>> - int i;
>> -
>> if (type_has_parent(ti)) {
>> object_init_with_type(obj, type_get_parent(ti));
>> }
>>
>> - for (i = 0; i < ti->num_interfaces; i++) {
>> - object_interface_init(obj, &ti->interfaces[i]);
>> - }
>> -
>> if (ti->instance_init) {
>> ti->instance_init(obj);
>> }
>> @@ -338,12 +354,6 @@ static void object_deinit(Object *obj, TypeImpl *type)
>> type->instance_finalize(obj);
>> }
>>
>> - while (obj->interfaces) {
>> - Interface *iface_obj = obj->interfaces->data;
>> - obj->interfaces = g_slist_delete_link(obj->interfaces,
>> obj->interfaces);
>> - object_delete(OBJECT(iface_obj));
>> - }
>> -
>> if (type_has_parent(type)) {
>> object_deinit(obj, type_get_parent(type));
>> }
>> @@ -390,22 +400,6 @@ void object_delete(Object *obj)
>> g_free(obj);
>> }
>>
>> -static bool type_is_ancestor(TypeImpl *type, TypeImpl *target_type)
>> -{
>> - assert(target_type);
>> -
>> - /* Check if typename is a direct ancestor of type */
>> - while (type) {
>> - if (type == target_type) {
>> - return true;
>> - }
>> -
>> - type = type_get_parent(type);
>> - }
>> -
>> - return false;
>> -}
>> -
>> static bool object_is_type(Object *obj, TypeImpl *target_type)
>> {
>> return !target_type || type_is_ancestor(obj->class->type, target_type);
>> @@ -414,7 +408,6 @@ static bool object_is_type(Object *obj, TypeImpl
>> *target_type)
>> Object *object_dynamic_cast(Object *obj, const char *typename)
>> {
>> TypeImpl *target_type = type_get_by_name(typename);
>> - GSList *i;
>>
>> /* Check if typename is a direct ancestor. Special-case TYPE_OBJECT,
>> * we want to go back from interfaces to the parent.
>> @@ -423,46 +416,18 @@ Object *object_dynamic_cast(Object *obj, const char
>> *typename)
>> return obj;
>> }
>>
>> - /* Check if obj is an interface and its containing object is a direct
>> - * ancestor of typename. In principle we could do this test at the very
>> - * beginning of object_dynamic_cast, avoiding a second call to
>> - * object_is_type. However, casting between interfaces is relatively
>> - * rare, and object_is_type(obj, type_interface) would fail almost
>> always.
>> - *
>> - * Perhaps we could add a magic value to the object header for increased
>> - * (run-time) type safety and to speed up tests like this one. If we
>> ever
>> - * do that we can revisit the order here.
>> - */
>> - if (object_is_type(obj, type_interface)) {
>> - assert(!obj->interfaces);
>> - obj = INTERFACE(obj)->obj;
>> - if (object_is_type(obj, target_type)) {
>> - return obj;
>> - }
>> - }
>> -
>> if (!target_type) {
>> return obj;
>> }
>>
>> - /* Check if obj has an interface of typename */
>> - for (i = obj->interfaces; i; i = i->next) {
>> - Interface *iface = i->data;
>> -
>> - if (object_is_type(OBJECT(iface), target_type)) {
>> - return OBJECT(iface);
>> - }
>> - }
>> -
>> return NULL;
>> }
>>
>> -
>> static void register_types(void)
>> {
>> static TypeInfo interface_info = {
>> .name = TYPE_INTERFACE,
>> - .instance_size = sizeof(Interface),
>> + .class_size = sizeof(InterfaceClass),
>> .abstract = true,
>> };
>>
>> @@ -491,16 +456,30 @@ ObjectClass *object_class_dynamic_cast(ObjectClass
>> *class,
>> {
>> TypeImpl *target_type = type_get_by_name(typename);
>> TypeImpl *type = class->type;
>> + ObjectClass *ret = NULL;
>>
>> - while (type) {
>> - if (type == target_type) {
>> - return class;
>> + if (type->num_interfaces && type_is_ancestor(target_type,
>> type_interface)) {
>> + int found = 0;
>> + GSList *i;
>> +
>> + for (i = class->interfaces; i; i = i->next) {
>> + ObjectClass *target_class = i->data;
>> +
>> + if (type_is_ancestor(target_class->type, target_type)) {
>> + ret = target_class;
>> + found++;
>> + }
>> }
>>
>> - type = type_get_parent(type);
>> + /* The match was ambiguous, don't allow a cast */
>> + if (found > 1) {
>> + ret = NULL;
>> + }
>> + } else if (type_is_ancestor(type, target_type)) {
>> + ret = class;
>> }
>>
>> - return NULL;
>> + return ret;
>> }
>>
>> ObjectClass *object_class_dynamic_cast_assert(ObjectClass *class,
>> @@ -517,6 +496,28 @@ ObjectClass
>> *object_class_dynamic_cast_assert(ObjectClass *class,
>> return ret;
>> }
>>
>> +Object *interface_dynamic_cast(Object *obj, const char *typename)
>> +{
>> + if (object_class_dynamic_cast(object_get_class(obj), typename)) {
>> + return obj;
>> + }
>> +
>> + return NULL;
>> +}
>> +
>> +Object *interface_dynamic_cast_assert(Object *obj, const char *typename)
>> +{
>> + Object *ret = interface_dynamic_cast(obj, typename);
>> +
>> + if (!ret) {
>> + fprintf(stderr, "Object %p is not an instance of type %s\n",
>> + obj, typename);
>> + abort();
>> + }
>> +
>> + return ret;
>> +}
>> +
>> const char *object_get_typename(Object *obj)
>> {
>> return obj->class->type->name;
>> @@ -883,12 +884,6 @@ void object_property_add_child(Object *obj, const char
>> *name,
>> {
>> gchar *type;
>>
>> - /* Registering an interface object in the composition tree will mightily
>> - * confuse object_get_canonical_path (which, on the other hand, knows
>> how
>> - * to get the canonical path of an interface object).
>> - */
>> - assert(!object_is_type(obj, type_interface));
>> -
>> type = g_strdup_printf("child<%s>", object_get_typename(OBJECT(child)));
>>
>> object_property_add(obj, name, type, object_get_child_property,
>> @@ -985,10 +980,6 @@ gchar *object_get_canonical_path(Object *obj)
>> Object *root = object_get_root();
>> char *newpath = NULL, *path = NULL;
>>
>> - if (object_is_type(obj, type_interface)) {
>> - obj = INTERFACE(obj)->obj;
>> - }
>> -
>> while (obj != root) {
>> ObjectProperty *prop = NULL;
>>
>
>
[Qemu-devel] [PATCH 2/3] qom: reimplement Interfaces, Anthony Liguori, 2012/06/13
[Qemu-devel] [PATCH 1/3] tests: fix dependency inclusion, Anthony Liguori, 2012/06/13
Re: [Qemu-devel] [PATCH 0/3] qom: refactor Interfaces, Paolo Bonzini, 2012/06/14
Re: [Qemu-devel] [PATCH 0/3] qom: refactor Interfaces, Peter Crosthwaite, 2012/06/15