[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 03/21] qom: Add core type system
From: |
Anthony Liguori |
Subject: |
[Qemu-devel] [PATCH 03/21] qom: Add core type system |
Date: |
Sun, 24 Jul 2011 20:44:35 -0500 |
This patch implements the basic type system used by QEMU Object Model. This
infrastructure supports the registration of classes and instantiation of
objects through a generic factory interface. Classes support polymophism and
single inheritance.
Interfaces can also be used to approximate multiple inheritance.
Signed-off-by: Anthony Liguori <address@hidden>
---
Makefile.qom | 4 +
Qconfig | 1 +
configure | 2 +-
include/qemu/type.h | 513 ++++++++++++++++++++++++++++++++++++++++++++++++++
qom/Makefile | 1 +
qom/Qconfig | 6 +
qom/type.c | 523 +++++++++++++++++++++++++++++++++++++++++++++++++++
7 files changed, 1049 insertions(+), 1 deletions(-)
create mode 100644 include/qemu/type.h
create mode 100644 qom/Makefile
create mode 100644 qom/Qconfig
create mode 100644 qom/type.c
diff --git a/Makefile.qom b/Makefile.qom
index 1b06970..34f1f91 100644
--- a/Makefile.qom
+++ b/Makefile.qom
@@ -9,3 +9,7 @@ config-qom.mak: $(SRC_PATH)/Qconfig $(QCONFIGS)
include $(SRC_PATH)/qapi/Makefile
common-obj-y += $(addprefix qapi/,$(qapi-obj-y))
+
+include $(SRC_PATH)/qom/Makefile
+common-obj-y += $(addprefix qom/,$(qom-obj-y))
+
diff --git a/Qconfig b/Qconfig
index cdf8f6c..889dfa6 100644
--- a/Qconfig
+++ b/Qconfig
@@ -1 +1,2 @@
source qapi/Qconfig
+source qom/Qconfig
diff --git a/configure b/configure
index 600da9b..93e5e97 100755
--- a/configure
+++ b/configure
@@ -3516,7 +3516,7 @@ DIRS="$DIRS pc-bios/spapr-rtas"
DIRS="$DIRS roms/seabios roms/vgabios"
DIRS="$DIRS fsdev ui"
DIRS="$DIRS qapi"
-DIRS="$DIRS qga"
+DIRS="$DIRS qga qom"
FILES="Makefile tests/Makefile"
FILES="$FILES tests/cris/Makefile tests/cris/.gdbinit"
FILES="$FILES pc-bios/optionrom/Makefile pc-bios/keymaps"
diff --git a/include/qemu/type.h b/include/qemu/type.h
new file mode 100644
index 0000000..170f485
--- /dev/null
+++ b/include/qemu/type.h
@@ -0,0 +1,513 @@
+/*
+ * QEMU Object Model
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ * Anthony Liguori <address@hidden>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef QEMU_TYPE_H
+#define QEMU_TYPE_H
+
+#include "qemu-common.h"
+#include <glib.h>
+
+#define MAX_ID (32 + 1)
+
+typedef uint64_t Type;
+
+typedef struct TypeClass TypeClass;
+typedef struct TypeInstance TypeInstance;
+typedef struct TypeInfo TypeInfo;
+
+typedef struct InterfaceClass InterfaceClass;
+typedef struct Interface Interface;
+typedef struct InterfaceInfo InterfaceInfo;
+
+/**
+ * @TypeClass:
+ *
+ * The base for all classes. The only thing that @TypeClass contains is an
+ * integer type handle.
+ */
+struct TypeClass
+{
+ /**
+ * @type the handle of the type for a class
+ */
+ Type type;
+};
+
+/**
+ * @TypeInstance:
+ *
+ * The base for all objects. The first member of this object is a pointer to
+ * a @TypeClass. Since C guarantees that the first member of a structure
+ * always begins at byte 0 of that structure, as long as any sub-object places
+ * its parent as the first member, we can cast directly to a @TypeInstance.
+ *
+ * As a result, @TypeInstance contains a reference to the objects type as its
+ * first member. This allows identification of the real type of the object at
+ * run time.
+ *
+ * @TypeInstance also contains a list of @Interfaces that this object
+ * implements.
+ */
+struct TypeInstance
+{
+ /**
+ * @class the type of the instantiated object.
+ */
+ TypeClass *class;
+
+ /**
+ * @id the name of the object
+ */
+ char id[MAX_ID];
+
+ /**
+ * @interfaces a list of @Interface objects implemented by this object
+ */
+ GSList *interfaces;
+};
+
+/**
+ * @TypeInfo:
+ *
+ */
+struct TypeInfo
+{
+ /**
+ * @name the name of the type
+ */
+ const char *name;
+
+ /**
+ * @parent the name of the parent type
+ */
+ const char *parent;
+
+ /**
+ * Instance Initialization
+ *
+ * This functions manage the instance construction and destruction of a
+ * type.
+ */
+
+ /**
+ * @instance_size the size of the object (derivative of @TypeInstance). If
+ * @instance_size is 0, then the size of the object will be the size of the
+ * parent object.
+ */
+ size_t instance_size;
+
+ /**
+ * @instance_init
+ *
+ * This function is called to initialize an object. The parent class will
+ * have already been initialized so the type is only responsible for
+ * initializing its own members.
+ */
+ void (*instance_init)(TypeInstance *obj);
+
+ /**
+ * @instance_finalize
+ *
+ * This function is called during object destruction. This is called
before
+ * the parent @instance_finalize function has been called. An object
should
+ * only free the members that are unique to its type in this function.
+ */
+ void (*instance_finalize)(TypeInstance *obj);
+
+ /**
+ * @abstract
+ *
+ * If this field is true, then the class is considered abstract and cannot
+ * be directly instantiated.
+ */
+ bool abstract;
+
+ /**
+ * Class Initialization
+ *
+ * Before an object is initialized, the class for the object must be
+ * initialized. There is only one class object for all instance objects
+ * that is created lazily.
+ *
+ * Classes are initialized by first initializing any parent classes (if
+ * necessary). After the parent class object has initialized, it will be
+ * copied into the current class object and any additional storage in the
+ * class object is zero filled.
+ *
+ * The effect of this is that classes automatically inherit any virtual
+ * function pointers that the parent class has already initialized. All
+ * other fields will be zero filled.
+ *
+ * After this initial copy, @base_init is invoked. This is meant to handle
+ * the case where a class may have a dynamic field that was copied via
+ * a shallow copy but needs to be deep copied. @base_init is called for
+ * each parent class but not for the class being instantiated.
+ *
+ * Once all of the parent classes have been initialized and their
@base_init
+ * functions have been called, @class_init is called to let the class being
+ * instantiated provide default initialize for it's virtual functions.
+ */
+
+ /**
+ * @class_size the size of the class object (derivative of @TypeClass) for
+ * this object. If @class_size is 0, then the size of the class will be
+ * assumed to be the size of the parent class. This allows a type to avoid
+ * implementing an explicit class type if they are not adding additional
+ * virtual functions.
+ */
+ size_t class_size;
+
+ /**
+ * @base_init
+ *
+ * This function is called after memcpy()'ing the base class into the new
+ * class to reinitialize any members that require deep copy.
+ */
+ void (*base_init)(TypeClass *klass);
+
+ /**
+ * @base_finalize
+ *
+ * This function is called during a class's destruction and is meant to
+ * allow any dynamic parameters allocated by @base_init to be released.
+ */
+ void (*base_finalize)(TypeClass *klass);
+
+ /**
+ * @class_init
+ *
+ * This function is called after all parent class initialization has
occured
+ * to allow a class to set its default virtual method pointers. This is
+ * also the function to use to override virtual methods from a parent
class.
+ */
+ void (*class_init)(TypeClass *klass);
+
+ /**
+ * @class_finalize
+ *
+ * This function is called during class destruction and is meant to release
+ * and dynamic parameters allocated by @class_init.
+ */
+ void (*class_finalize)(TypeClass *klass);
+
+ /**
+ * Interfaces
+ *
+ * Interfaces allow a limited form of multiple inheritance. Instances are
+ * similar to normal types except for the fact that are only defined by
+ * their classes and never carry any state. You can cast an object to one
+ * of its @Interface types and vice versa.
+ */
+
+ /**
+ * @interfaces the list of interfaces associated with this type. This
+ * should point to a static array that's terminated with a zero filled
+ * element.
+ */
+ InterfaceInfo *interfaces;
+};
+
+/**
+ * @TYPE_INSTANCE
+ *
+ * Converts an object to a @TypeInstance. Since all objects are
@TypeInstances,
+ * this function will always succeed.
+ */
+#define TYPE_INSTANCE(obj) \
+ ((TypeInstance *)(obj))
+
+/**
+ * @TYPE_CHECK
+ *
+ * A type safe version of @type_dynamic_cast_assert. Typically each class will
+ * define a macro based on this type to perform type safe dynamic_casts to
+ * this object type.
+ *
+ * If an invalid object is passed to this function, a run time assert will be
+ * generated.
+ */
+#define TYPE_CHECK(type, obj, name) \
+ ((type *)type_dynamic_cast_assert((TypeInstance *)(obj), (name)))
+
+/**
+ * @TYPE_CLASS_CHECK
+ *
+ * A type safe version of @type_check_class. This macro is typically wrapped
+ * by each type to perform type safe casts of a class to a specific class type.
+ */
+#define TYPE_CLASS_CHECK(class, obj, name) \
+ ((class *)type_check_class((TypeClass *)(obj), (name)))
+
+/**
+ * @TYPE_GET_CLASS
+ *
+ * This function will return a specific class for a given object. Its
generally
+ * used by each type to provide a type safe macro to get a specific class type
+ * from an object.
+ */
+#define TYPE_GET_CLASS(class, obj, name) \
+ TYPE_CLASS_CHECK(class, type_get_class(TYPE_INSTANCE(obj)), name)
+
+/**
+ * @Interface:
+ *
+ * The base for all Interfaces. This is a subclass of TypeInstance.
Subclasses
+ * of @Interface should never have an instance that contains anything other
than
+ * a single @Interface member.
+ */
+struct Interface
+{
+ /**
+ * @parent base class
+ */
+ TypeInstance parent;
+
+ /* private */
+
+ /**
+ * @obj a pointer to the object that implements this interface. This is
+ * used to allow casting from an interface to the base object.
+ */
+ TypeInstance *obj;
+};
+
+/**
+ * @InterfaceClass:
+ *
+ * The class for all interfaces. Subclasses of this class should only add
+ * virtual methods.
+ */
+struct InterfaceClass
+{
+ /**
+ * @parent_class the base class
+ */
+ TypeClass parent_class;
+};
+
+/**
+ * @InterfaceInfo:
+ *
+ * The information associated with an interface.
+ */
+struct InterfaceInfo
+{
+ /**
+ * @type the name of the interface
+ */
+ const char *type;
+
+ /**
+ * @interface_initfn 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.
+ */
+ void (*interface_initfn)(TypeClass *class);
+};
+
+#define TYPE_INTERFACE "interface"
+#define INTERFACE(obj) TYPE_CHECK(Interface, obj, TYPE_INTERFACE)
+
+/**
+ * @type_new:
+ *
+ * This function will initialize a new object using heap allocated memory.
This
+ * function should be paired with @type_delete to free the resources associated
+ * with the object.
+ *
+ * @typename: The name of the type of the object to instantiate
+ *
+ * @id: The id of the object. This must be unique.
+ *
+ * Returns: The newly allocated and instantiated object.
+ *
+ */
+TypeInstance *type_new(const char *typename, const char *id);
+
+/**
+ * @type_delete:
+ *
+ * Finalize an object and then free the memory associated with it. This should
+ * be paired with @type_new to free the resources associated with an object.
+ *
+ * @obj: The object to free.
+ *
+ */
+void type_delete(TypeInstance *obj);
+
+/**
+ * @type_initialize:
+ *
+ * This function will initialize an object. The memory for the object should
+ * have already been allocated.
+ *
+ * @obj: A pointer to the memory to be used for the object.
+ *
+ * @typename: The name of the type of the object to instantiate
+ *
+ * @id: The id of the object. This must be unique.
+ *
+ */
+void type_initialize(void *obj, const char *typename, const char *id);
+
+/**
+ * @type_finalize:
+ *
+ * This function destroys and object without freeing the memory associated with
+ * it.
+ *
+ * @obj:
+ *
+ */
+void type_finalize(void *obj);
+
+/**
+ * @type_dynamic_cast:
+ *
+ * This function will determine if @obj is-a @typename. @obj can refer to an
+ * object or an interface associated with an object.
+ *
+ * @obj: The object to cast.
+ *
+ * @typename: The @typename
+ *
+ * Returns:
+ *
+ */
+TypeInstance *type_dynamic_cast(TypeInstance *obj, const char *typename);
+
+/**
+ * @type_dynamic_cast_assert:
+ *
+ * @obj:
+ *
+ * @typename:
+ *
+ * Returns:
+ *
+ */
+TypeInstance *type_dynamic_cast_assert(TypeInstance *obj, const char
*typename);
+
+/**
+ * @type_is_type:
+ *
+ * @obj:
+ *
+ * @typename:
+ *
+ * Returns:
+ *
+ */
+bool type_is_type(TypeInstance *obj, const char *typename);
+
+/**
+ * @type_get_class:
+ *
+ * @obj:
+ *
+ * Returns:
+ *
+ */
+TypeClass *type_get_class(TypeInstance *obj);
+
+/**
+ * @type_get_id:
+ *
+ * @obj:
+ *
+ * Returns:
+ *
+ */
+const char *type_get_id(TypeInstance *obj);
+
+/**
+ * @type_get_type:
+ *
+ * @obj:
+ *
+ * Returns:
+ */
+const char *type_get_type(TypeInstance *obj);
+
+/**
+ * @type_get_super:
+ *
+ * @obj:
+ *
+ * Returns:
+ */
+TypeClass *type_get_super(TypeInstance *obj);
+
+/**/
+
+/**
+ * @type_register_static:
+ *
+ * @info:
+ *
+ * Returns:
+ */
+Type type_register_static(const TypeInfo *info);
+
+/**
+ * @type_find_by_id:
+ *
+ * @id:
+ *
+ * Returns:
+ *
+ */
+TypeInstance *type_find_by_id(const char *id);
+
+/**
+ * @type_check_class:
+ *
+ * @obj:
+ *
+ * @typename:
+ *
+ * Returns:
+ */
+TypeClass *type_check_class(TypeClass *obj, const char *typename);
+
+/**
+ * @type_get_by_name:
+ *
+ * @name:
+ *
+ * Returns:
+ */
+Type type_get_by_name(const char *name);
+
+/**
+ * @type_get_name:
+ *
+ * @type:
+ *
+ * Returns:
+ */
+const char *type_get_name(Type type);
+
+/**
+ * @type_foreach:
+ *
+ * @enumfn:
+ *
+ * @opaque:
+ *
+ */
+void type_foreach(void (*enumfn)(TypeInstance *obj, void *opaque),
+ void *opaque);
+
+#endif
diff --git a/qom/Makefile b/qom/Makefile
new file mode 100644
index 0000000..838054f
--- /dev/null
+++ b/qom/Makefile
@@ -0,0 +1 @@
+qom-obj-$(CONFIG_QOM) += type.o
diff --git a/qom/Qconfig b/qom/Qconfig
new file mode 100644
index 0000000..16660b4
--- /dev/null
+++ b/qom/Qconfig
@@ -0,0 +1,6 @@
+config QOM
+ bool "QEMU Object Model Support"
+ default y
+ depends on QAPI
+ help
+ This is the core object model used by QEMU. If in doubt, say y here.
diff --git a/qom/type.c b/qom/type.c
new file mode 100644
index 0000000..28e8114
--- /dev/null
+++ b/qom/type.c
@@ -0,0 +1,523 @@
+/*
+ * QEMU Object Model
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ * Anthony Liguori <address@hidden>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/type.h"
+#include <glib.h>
+
+#define MAX_INTERFACES 32
+
+typedef struct InterfaceImpl
+{
+ const char *parent;
+ void (*interface_initfn)(TypeClass *class);
+ Type type;
+} InterfaceImpl;
+
+typedef struct TypeImpl
+{
+ const char *name;
+ Type type;
+
+ size_t class_size;
+
+ size_t instance_size;
+
+ void (*base_init)(TypeClass *klass);
+ void (*base_finalize)(TypeClass *klass);
+
+ void (*class_init)(TypeClass *klass);
+ void (*class_finalize)(TypeClass *klass);
+
+ void (*instance_init)(TypeInstance *obj);
+ void (*instance_finalize)(TypeInstance *obj);
+
+ bool abstract;
+
+ const char *parent;
+
+ TypeClass *class;
+
+ int num_interfaces;
+ InterfaceImpl interfaces[MAX_INTERFACES];
+} TypeImpl;
+
+static int num_types = 1;
+static TypeImpl type_table[128];
+
+Type type_register_static(const TypeInfo *info)
+{
+ Type type = num_types++;
+ TypeImpl *ti;
+
+ ti = &type_table[type];
+
+ assert(info->name != NULL);
+
+ ti->name = info->name;
+ ti->parent = info->parent;
+ ti->type = type;
+
+ ti->class_size = info->class_size;
+ ti->instance_size = info->instance_size;
+
+ ti->base_init = info->base_init;
+ ti->base_finalize = info->base_finalize;
+
+ ti->class_init = info->class_init;
+ ti->class_finalize = info->class_finalize;
+
+ ti->instance_init = info->instance_init;
+ ti->instance_finalize = info->instance_finalize;
+
+ 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++;
+ }
+ }
+
+ return type;
+}
+
+static Type type_register_anonymous(const TypeInfo *info)
+{
+ Type type = num_types++;
+ TypeImpl *ti;
+ char buffer[32];
+ static int count;
+
+ ti = &type_table[type];
+
+ snprintf(buffer, sizeof(buffer), "<anonymous-%d>", count++);
+ ti->name = qemu_strdup(buffer);
+ ti->parent = qemu_strdup(info->parent);
+ ti->type = type;
+
+ ti->class_size = info->class_size;
+ ti->instance_size = info->instance_size;
+
+ ti->base_init = info->base_init;
+ ti->base_finalize = info->base_finalize;
+
+ ti->class_init = info->class_init;
+ ti->class_finalize = info->class_finalize;
+
+ ti->instance_init = info->instance_init;
+ ti->instance_finalize = info->instance_finalize;
+
+ 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++;
+ }
+ }
+
+ return type;
+}
+
+static TypeImpl *type_get_instance(Type type)
+{
+ assert(type != 0);
+ assert(type < num_types);
+
+ return &type_table[type];
+}
+
+Type type_get_by_name(const char *name)
+{
+ int i;
+
+ if (name == NULL) {
+ return 0;
+ }
+
+ for (i = 1; i < num_types; i++) {
+ if (strcmp(name, type_table[i].name) == 0) {
+ return i;
+ }
+ }
+
+ return 0;
+}
+
+static void type_class_base_init(TypeImpl *base_ti, const char *typename)
+{
+ TypeImpl *ti;
+
+ if (!typename) {
+ return;
+ }
+
+ ti = type_get_instance(type_get_by_name(typename));
+
+ type_class_base_init(base_ti, ti->parent);
+
+ if (ti->base_init) {
+ ti->base_init(base_ti->class);
+ }
+}
+
+static size_t type_class_get_size(TypeImpl *ti)
+{
+ if (ti->class_size) {
+ return ti->class_size;
+ }
+
+ if (ti->parent) {
+ return
type_class_get_size(type_get_instance(type_get_by_name(ti->parent)));
+ }
+
+ return sizeof(TypeClass);
+}
+
+static void type_class_interface_init(TypeImpl *ti, InterfaceImpl *iface)
+{
+ TypeInfo info = {
+ .instance_size = sizeof(Interface),
+ .parent = iface->parent,
+ .class_size = sizeof(InterfaceClass),
+ .class_init = iface->interface_initfn,
+ .abstract = true,
+ };
+
+ iface->type = type_register_anonymous(&info);
+}
+
+static void type_class_init(TypeImpl *ti)
+{
+ size_t class_size = sizeof(TypeClass);
+ int i;
+
+ if (ti->class) {
+ return;
+ }
+
+ ti->class_size = type_class_get_size(ti);
+
+ ti->class = qemu_malloc(ti->class_size);
+ ti->class->type = ti->type;
+
+ if (ti->parent) {
+ TypeImpl *ti_parent;
+
+ ti_parent = type_get_instance(type_get_by_name(ti->parent));
+
+ type_class_init(ti_parent);
+
+ class_size = ti_parent->class_size;
+ assert(ti_parent->class_size <= ti->class_size);
+
+ memcpy((void *)ti->class + sizeof(TypeClass),
+ (void *)ti_parent->class + sizeof(TypeClass),
+ ti_parent->class_size - sizeof(TypeClass));
+ }
+
+ memset((void *)ti->class + class_size, 0, ti->class_size - class_size);
+
+ type_class_base_init(ti, ti->parent);
+
+ for (i = 0; i < ti->num_interfaces; i++) {
+ type_class_interface_init(ti, &ti->interfaces[i]);
+ }
+
+ if (ti->class_init) {
+ ti->class_init(ti->class);
+ }
+}
+
+static void type_instance_interface_init(TypeInstance *obj, InterfaceImpl
*iface)
+{
+ TypeImpl *ti = type_get_instance(iface->type);
+ Interface *iface_obj;
+ static int count;
+ char buffer[32];
+
+ snprintf(buffer, sizeof(buffer), "__anonymous_%d", count++);
+ iface_obj = INTERFACE(type_new(ti->name, buffer));
+ iface_obj->obj = obj;
+
+ obj->interfaces = g_slist_prepend(obj->interfaces, iface_obj);
+}
+
+static void type_instance_init(TypeInstance *obj, const char *typename)
+{
+ TypeImpl *ti = type_get_instance(type_get_by_name(typename));
+ int i;
+
+ if (ti->parent) {
+ type_instance_init(obj, ti->parent);
+ }
+
+ for (i = 0; i < ti->num_interfaces; i++) {
+ type_instance_interface_init(obj, &ti->interfaces[i]);
+ }
+
+ if (ti->instance_init) {
+ ti->instance_init(obj);
+ }
+}
+
+static GHashTable *global_object_table;
+
+void type_initialize(void *data, const char *typename, const char *id)
+{
+ TypeImpl *ti = type_get_instance(type_get_by_name(typename));
+ TypeInstance *obj = data;
+
+ g_assert(ti->instance_size >= sizeof(TypeClass));
+
+ type_class_init(ti);
+
+ g_assert(ti->abstract == false);
+
+ memset(obj, 0, ti->instance_size);
+
+ obj->class = ti->class;
+ snprintf(obj->id, sizeof(obj->id), "%s", id);
+
+ if (global_object_table == NULL) {
+ global_object_table = g_hash_table_new(g_str_hash, g_str_equal);
+ }
+
+ g_hash_table_insert(global_object_table, obj->id, obj);
+
+ type_instance_init(obj, typename);
+}
+
+static void type_instance_finalize(TypeInstance *obj, const char *typename)
+{
+ TypeImpl *ti = type_get_instance(type_get_by_name(typename));
+
+ if (ti->instance_finalize) {
+ ti->instance_finalize(obj);
+ }
+
+ while (obj->interfaces) {
+ Interface *iface_obj = obj->interfaces->data;
+ obj->interfaces = g_slist_delete_link(obj->interfaces,
obj->interfaces);
+ type_delete(TYPE_INSTANCE(iface_obj));
+ }
+
+ if (ti->parent) {
+ type_instance_init(obj, ti->parent);
+ }
+}
+
+void type_finalize(void *data)
+{
+ TypeInstance *obj = data;
+ TypeImpl *ti = type_get_instance(obj->class->type);
+
+ g_hash_table_remove(global_object_table, obj->id);
+
+ type_instance_finalize(obj, ti->name);
+}
+
+const char *type_get_name(Type type)
+{
+ TypeImpl *ti = type_get_instance(type);
+ return ti->name;
+}
+
+TypeInstance *type_new(const char *typename, const char *id)
+{
+ TypeImpl *ti = type_get_instance(type_get_by_name(typename));
+ TypeInstance *obj;
+
+ obj = qemu_malloc(ti->instance_size);
+ type_initialize(obj, typename, id);
+
+ return obj;
+}
+
+void type_delete(TypeInstance *obj)
+{
+ type_finalize(obj);
+ qemu_free(obj);
+}
+
+TypeInstance *type_find_by_id(const char *id)
+{
+ gpointer data;
+
+ if (global_object_table == NULL) {
+ return NULL;
+ }
+
+ data = g_hash_table_lookup(global_object_table, id);
+
+ if (!data) {
+ return NULL;
+ }
+
+ return TYPE_INSTANCE(data);
+}
+
+bool type_is_type(TypeInstance *obj, const char *typename)
+{
+ Type target_type = type_get_by_name(typename);
+ Type type = obj->class->type;
+ GSList *i;
+
+ /* Check if typename is a direct ancestor of type */
+ while (type) {
+ TypeImpl *ti = type_get_instance(type);
+
+ if (ti->type == target_type) {
+ return true;
+ }
+
+ type = type_get_by_name(ti->parent);
+ }
+
+ /* Check if obj has an interface of typename */
+ for (i = obj->interfaces; i; i = i->next) {
+ Interface *iface = i->data;
+
+ if (type_is_type(TYPE_INSTANCE(iface), typename)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+TypeInstance *type_dynamic_cast(TypeInstance *obj, const char *typename)
+{
+ GSList *i;
+
+ /* Check if typename is a direct ancestor */
+ if (type_is_type(obj, typename)) {
+ return obj;
+ }
+
+ /* Check if obj has an interface of typename */
+ for (i = obj->interfaces; i; i = i->next) {
+ Interface *iface = i->data;
+
+ if (type_is_type(TYPE_INSTANCE(iface), typename)) {
+ return TYPE_INSTANCE(iface);
+ }
+ }
+
+ /* Check if obj is an interface and it's containing object is a direct
ancestor of typename */
+ if (type_is_type(obj, TYPE_INTERFACE)) {
+ Interface *iface = INTERFACE(obj);
+
+ if (type_is_type(iface->obj, typename)) {
+ return iface->obj;
+ }
+ }
+
+ return NULL;
+}
+
+
+static void register_interface(void)
+{
+ static TypeInfo interface_info = {
+ .name = TYPE_INTERFACE,
+ .instance_size = sizeof(Interface),
+ .abstract = true,
+ };
+
+ type_register_static(&interface_info);
+}
+
+device_init(register_interface);
+
+TypeInstance *type_dynamic_cast_assert(TypeInstance *obj, const char *typename)
+{
+ TypeInstance *inst;
+
+ inst = type_dynamic_cast(obj, typename);
+
+ if (!inst) {
+ fprintf(stderr, "Object %p is not an instance of type %s\n", obj,
typename);
+ abort();
+ }
+
+ return inst;
+}
+
+TypeClass *type_check_class(TypeClass *class, const char *typename)
+{
+ Type target_type = type_get_by_name(typename);
+ Type type = class->type;
+
+ while (type) {
+ TypeImpl *ti = type_get_instance(type);
+
+ if (ti->type == target_type) {
+ return class;
+ }
+
+ type = type_get_by_name(ti->parent);
+ }
+
+ fprintf(stderr, "Object %p is not an instance of type %d\n", class,
(int)type);
+ abort();
+
+ return NULL;
+}
+
+const char *type_get_id(TypeInstance *obj)
+{
+ return obj->id;
+}
+
+const char *type_get_type(TypeInstance *obj)
+{
+ return type_get_name(obj->class->type);
+}
+
+TypeClass *type_get_class(TypeInstance *obj)
+{
+ return obj->class;
+}
+
+typedef struct TypeForeachData
+{
+ void (*enumfn)(TypeInstance *obj, void *opaque);
+ void *opaque;
+} TypeForeachData;
+
+static void type_foreach_tramp(gpointer key, gpointer value, gpointer opaque)
+{
+ TypeForeachData *data = opaque;
+ data->enumfn(TYPE_INSTANCE(value), data->opaque);
+}
+
+void type_foreach(void (*enumfn)(TypeInstance *obj, void *opaque), void
*opaque)
+{
+ TypeForeachData data = {
+ .enumfn = enumfn,
+ .opaque = opaque,
+ };
+
+ g_hash_table_foreach(global_object_table, type_foreach_tramp, &data);
+}
+
+TypeClass *type_get_super(TypeInstance *obj)
+{
+ return
type_get_instance(type_get_by_name(type_get_instance(obj->class->type)->parent))->class;
+}
+
--
1.7.4.1
- [Qemu-devel] [RFC][PATCH 0/21] QEMU Object Model, Anthony Liguori, 2011/07/24
- [Qemu-devel] [PATCH 02/21] qom: convert QAPI to use Qconfig build system, Anthony Liguori, 2011/07/24
- [Qemu-devel] [PATCH 04/21] qom: add Plug class, Anthony Liguori, 2011/07/24
- [Qemu-devel] [PATCH 06/21] plug: add socket property type, Anthony Liguori, 2011/07/24
- [Qemu-devel] [PATCH 01/21] qom: add make infrastructure, Anthony Liguori, 2011/07/24
- [Qemu-devel] [PATCH 07/21] plug: add generated property types, Anthony Liguori, 2011/07/24
- [Qemu-devel] [PATCH 03/21] qom: Add core type system,
Anthony Liguori <=
- [Qemu-devel] [PATCH 05/21] plug: add Plug property type, Anthony Liguori, 2011/07/24
- [Qemu-devel] [PATCH 10/21] qom: add plug_get QMP command, Anthony Liguori, 2011/07/24
- [Qemu-devel] [PATCH 11/21] qom: add plug_set QMP command, Anthony Liguori, 2011/07/24
- [Qemu-devel] [PATCH 08/21] qom: add plug_create QMP command, Anthony Liguori, 2011/07/24
- [Qemu-devel] [PATCH 13/21] qom: add plug_destroy command, Anthony Liguori, 2011/07/24
- [Qemu-devel] [PATCH 16/21] qom-devices: add a Pin class, Anthony Liguori, 2011/07/24
- [Qemu-devel] [PATCH 17/21] qom: add CharDriver class, Anthony Liguori, 2011/07/24
- [Qemu-devel] [PATCH 12/21] qom: add plug_list_props QMP command, Anthony Liguori, 2011/07/24
- [Qemu-devel] [PATCH 15/21] qom: add Device class, Anthony Liguori, 2011/07/24