aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--Makefile.hw1
-rw-r--r--Makefile.objs3
-rw-r--r--Makefile.target2
-rwxr-xr-xconfigure2
-rw-r--r--include/qemu/object.h436
-rw-r--r--qom/Makefile1
-rw-r--r--qom/object.c485
8 files changed, 931 insertions, 1 deletions
diff --git a/Makefile b/Makefile
index 917fb9bd7d..d172cbfab6 100644
--- a/Makefile
+++ b/Makefile
@@ -114,6 +114,8 @@ QEMU_CFLAGS+=$(CURL_CFLAGS)
QEMU_CFLAGS+=$(GLIB_CFLAGS)
+QEMU_CFLAGS += -I$(SRC_PATH)/include
+
ui/cocoa.o: ui/cocoa.m
ui/sdl.o audio/sdlaudio.o ui/sdl_zoom.o baum.o: QEMU_CFLAGS += $(SDL_CFLAGS)
diff --git a/Makefile.hw b/Makefile.hw
index 63eb7e40be..7b8d068c94 100644
--- a/Makefile.hw
+++ b/Makefile.hw
@@ -11,6 +11,7 @@ $(call set-vpath, $(SRC_PATH):$(SRC_PATH)/hw)
QEMU_CFLAGS+=-I..
QEMU_CFLAGS += $(GLIB_CFLAGS)
+QEMU_CFLAGS += -I$(SRC_PATH)/include
include $(SRC_PATH)/Makefile.objs
diff --git a/Makefile.objs b/Makefile.objs
index 06a147b0b0..b94262524d 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -124,6 +124,9 @@ common-obj-$(CONFIG_WIN32) += version.o
common-obj-$(CONFIG_SPICE) += ui/spice-core.o ui/spice-input.o ui/spice-display.o spice-qemu-char.o
+include $(SRC_PATH)/qom/Makefile
+common-obj-y += $(addprefix qom/, $(qom-y))
+
audio-obj-y = audio.o noaudio.o wavaudio.o mixeng.o
audio-obj-$(CONFIG_SDL) += sdlaudio.o
audio-obj-$(CONFIG_OSS) += ossaudio.o
diff --git a/Makefile.target b/Makefile.target
index 3c850854cc..68481a3a6c 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -22,6 +22,8 @@ QEMU_CFLAGS += -I.. -I$(TARGET_PATH) -DNEED_CPU_H
include $(SRC_PATH)/Makefile.objs
+QEMU_CFLAGS+=-I$(SRC_PATH)/include
+
ifdef CONFIG_USER_ONLY
# user emulator name
QEMU_PROG=qemu-$(TARGET_ARCH2)
diff --git a/configure b/configure
index 69fb239749..f69e08f575 100755
--- a/configure
+++ b/configure
@@ -3785,7 +3785,7 @@ DIRS="$DIRS pc-bios/spapr-rtas"
DIRS="$DIRS roms/seabios roms/vgabios"
DIRS="$DIRS fsdev ui"
DIRS="$DIRS qapi qapi-generated"
-DIRS="$DIRS qga trace"
+DIRS="$DIRS qga trace qom"
FILES="Makefile tests/tcg/Makefile qdict-test-data.txt"
FILES="$FILES tests/tcg/cris/Makefile tests/tcg/cris/.gdbinit"
FILES="$FILES pc-bios/optionrom/Makefile pc-bios/keymaps"
diff --git a/include/qemu/object.h b/include/qemu/object.h
new file mode 100644
index 0000000000..ba37850a08
--- /dev/null
+++ b/include/qemu/object.h
@@ -0,0 +1,436 @@
+/*
+ * QEMU Object Model
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.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 QEMU_OBJECT_H
+#define QEMU_OBJECT_H
+
+#include <glib.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+struct TypeImpl;
+typedef struct TypeImpl *Type;
+
+typedef struct ObjectClass ObjectClass;
+typedef struct Object Object;
+
+typedef struct TypeInfo TypeInfo;
+
+typedef struct InterfaceClass InterfaceClass;
+typedef struct InterfaceInfo InterfaceInfo;
+
+#define TYPE_OBJECT NULL
+
+/**
+ * SECTION:object.h
+ * @title:Base Object Type System
+ * @short_description: interfaces for creating new types and objects
+ *
+ * The QEMU Object Model provides a framework for registering user creatable
+ * types and instantiating objects from those types. QOM provides the following
+ * features:
+ *
+ * - System for dynamically registering types
+ * - Support for single-inheritance of types
+ * - Multiple inheritance of stateless interfaces
+ *
+ * <example>
+ * <title>Creating a minimal type</title>
+ * <programlisting>
+ * #include "qdev.h"
+ *
+ * #define TYPE_MY_DEVICE "my-device"
+ *
+ * typedef struct MyDevice
+ * {
+ * DeviceState parent;
+ *
+ * int reg0, reg1, reg2;
+ * } MyDevice;
+ *
+ * static TypeInfo my_device_info = {
+ * .name = TYPE_MY_DEVICE,
+ * .parent = TYPE_DEVICE,
+ * .instance_size = sizeof(MyDevice),
+ * };
+ *
+ * static void my_device_module_init(void)
+ * {
+ * type_register_static(&my_device_info);
+ * }
+ *
+ * device_init(my_device_module_init);
+ * </programlisting>
+ * </example>
+ *
+ * In the above example, we create a simple type that is described by #TypeInfo.
+ * #TypeInfo describes information about the type including what it inherits
+ * from, the instance and class size, and constructor/destructor hooks.
+ *
+ * Every type has an #ObjectClass associated with it. #ObjectClass derivatives
+ * are instantiated dynamically but there is only ever one instance for any
+ * given type. The #ObjectClass typically holds a table of function pointers
+ * for the virtual methods implemented by this type.
+ *
+ * Using object_new(), a new #Object derivative will be instantiated. You can
+ * cast an #Object to a subclass (or base-class) type using
+ * object_dynamic_cast(). You typically want to define a macro wrapper around
+ * object_dynamic_cast_assert() to make it easier to convert to a specific type.
+ *
+ * # 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.
+ *
+ * Once all of the parent classes have been initialized, #TypeInfo::class_init
+ * is called to let the class being instantiated provide default initialize for
+ * it's virtual functions.
+ *
+ * # 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 dynamically cast an object
+ * to one of its #Interface types and vice versa.
+ */
+
+/**
+ * ObjectClass:
+ *
+ * The base for all classes. The only thing that #ObjectClass contains is an
+ * integer type handle.
+ */
+struct ObjectClass
+{
+ /*< private >*/
+ Type type;
+};
+
+/**
+ * Object:
+ *
+ * The base for all objects. The first member of this object is a pointer to
+ * a #ObjectClass. 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 #Object.
+ *
+ * As a result, #Object contains a reference to the objects type as its
+ * first member. This allows identification of the real type of the object at
+ * run time.
+ *
+ * #Object also contains a list of #Interfaces that this object
+ * implements.
+ */
+struct Object
+{
+ /*< private >*/
+ ObjectClass *class;
+
+ GSList *interfaces;
+};
+
+/**
+ * TypeInfo:
+ * @name: The name of the type.
+ * @parent: The name of the parent type.
+ * @instance_size: The size of the object (derivative of #Object). If
+ * @instance_size is 0, then the size of the object will be the size of the
+ * parent object.
+ * @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.
+ * @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.
+ * @abstract: If this field is true, then the class is considered abstract and
+ * cannot be directly instantiated.
+ * @class_size: The size of the class object (derivative of #ObjectClass)
+ * 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.
+ * @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.
+ * @class_finalize: This function is called during class destruction and is
+ * meant to release and dynamic parameters allocated by @class_init.
+ * @class_data: Data to pass to the @class_init and @class_finalize functions.
+ * This can be useful when building dynamic classes.
+ * @interfaces: The list of interfaces associated with this type. This
+ * should point to a static array that's terminated with a zero filled
+ * element.
+ */
+struct TypeInfo
+{
+ const char *name;
+ const char *parent;
+
+ size_t instance_size;
+ void (*instance_init)(Object *obj);
+ void (*instance_finalize)(Object *obj);
+
+ bool abstract;
+ size_t class_size;
+
+ void (*class_init)(ObjectClass *klass, void *data);
+ void (*class_finalize)(ObjectClass *klass, void *data);
+ void *class_data;
+
+ InterfaceInfo *interfaces;
+};
+
+/**
+ * OBJECT:
+ * @obj: A derivative of #Object
+ *
+ * Converts an object to a #Object. Since all objects are #Objects,
+ * this function will always succeed.
+ */
+#define OBJECT(obj) \
+ ((Object *)(obj))
+
+/**
+ * OBJECT_CHECK:
+ * @type: The C type to use for the return value.
+ * @obj: A derivative of @type to cast.
+ * @name: The QOM typename of @type
+ *
+ * A type safe version of @object_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 OBJECT_CHECK(type, obj, name) \
+ ((type *)object_dynamic_cast_assert((Object *)(obj), (name)))
+
+/**
+ * OBJECT_CLASS_CHECK:
+ * @class: The C type to use for the return value.
+ * @obj: A derivative of @type to cast.
+ * @name: the QOM typename of @class.
+ *
+ * A type safe version of @object_check_class. This macro is typically wrapped
+ * by each type to perform type safe casts of a class to a specific class type.
+ */
+#define OBJECT_CLASS_CHECK(class, obj, name) \
+ ((class *)object_class_dynamic_cast_assert((ObjectClass *)(obj), (name)))
+
+/**
+ * OBJECT_GET_CLASS:
+ * @class: The C type to use for the return value.
+ * @obj: The object to obtain the class for.
+ * @name: The QOM typename of @obj.
+ *
+ * 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 OBJECT_GET_CLASS(class, obj, name) \
+ OBJECT_CLASS_CHECK(class, object_get_class(OBJECT(obj)), name)
+
+#define OBJECT_CLASS(class) \
+ ((ObjectClass *)(class))
+
+/**
+ * InterfaceClass:
+ * @parent_class: the base class
+ *
+ * The class for all interfaces. Subclasses of this class should only add
+ * virtual methods.
+ */
+struct InterfaceClass
+{
+ ObjectClass parent_class;
+};
+
+/**
+ * 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.
+ *
+ * The information associated with an interface.
+ */
+struct InterfaceInfo
+{
+ const char *type;
+
+ void (*interface_initfn)(ObjectClass *class, void *data);
+};
+
+#define TYPE_INTERFACE "interface"
+
+/**
+ * object_new:
+ * @typename: The name of the type of the object to instantiate.
+ *
+ * This function will initialize a new object using heap allocated memory. This
+ * function should be paired with object_delete() to free the resources
+ * associated with the object.
+ *
+ * Returns: The newly allocated and instantiated object.
+ */
+Object *object_new(const char *typename);
+
+/**
+ * object_new_with_type:
+ * @type: The type of the object to instantiate.
+ *
+ * This function will initialize a new object using heap allocated memory. This
+ * function should be paired with object_delete() to free the resources
+ * associated with the object.
+ *
+ * Returns: The newly allocated and instantiated object.
+ */
+Object *object_new_with_type(Type type);
+
+/**
+ * object_delete:
+ * @obj: The object to free.
+ *
+ * Finalize an object and then free the memory associated with it. This should
+ * be paired with object_new() to free the resources associated with an object.
+ */
+void object_delete(Object *obj);
+
+/**
+ * object_initialize_with_type:
+ * @obj: A pointer to the memory to be used for the object.
+ * @type: The type of the object to instantiate.
+ *
+ * This function will initialize an object. The memory for the object should
+ * have already been allocated.
+ */
+void object_initialize_with_type(void *data, Type type);
+
+/**
+ * object_initialize:
+ * @obj: A pointer to the memory to be used for the object.
+ * @typename: The name of the type of the object to instantiate.
+ *
+ * This function will initialize an object. The memory for the object should
+ * have already been allocated.
+ */
+void object_initialize(void *obj, const char *typename);
+
+/**
+ * object_finalize:
+ * @obj: The object to finalize.
+ *
+ * This function destroys and object without freeing the memory associated with
+ * it.
+ */
+void object_finalize(void *obj);
+
+/**
+ * object_dynamic_cast:
+ * @obj: The object to cast.
+ * @typename: The @typename to cast to.
+ *
+ * This function will determine if @obj is-a @typename. @obj can refer to an
+ * object or an interface associated with an object.
+ *
+ * Returns: This function returns @obj on success or #NULL on failure.
+ */
+Object *object_dynamic_cast(Object *obj, const char *typename);
+
+/**
+ * @object_dynamic_cast_assert:
+ *
+ * See object_dynamic_cast() for a description of the parameters of this
+ * function. The only difference in behavior is that this function asserts
+ * instead of returning #NULL on failure.
+ */
+Object *object_dynamic_cast_assert(Object *obj, const char *typename);
+
+/**
+ * object_get_class:
+ * @obj: A derivative of #Object
+ *
+ * Returns: The #ObjectClass of the type associated with @obj.
+ */
+ObjectClass *object_get_class(Object *obj);
+
+/**
+ * object_get_typename:
+ * @obj: A derivative of #Object.
+ *
+ * Returns: The QOM typename of @obj.
+ */
+const char *object_get_typename(Object *obj);
+
+/**
+ * type_register_static:
+ * @info: The #TypeInfo of the new type.
+ *
+ * @info and all of the strings it points to should exist for the life time
+ * that the type is registered.
+ *
+ * Returns: 0 on failure, the new #Type on success.
+ */
+Type type_register_static(const TypeInfo *info);
+
+/**
+ * type_register:
+ * @info: The #TypeInfo of the new type
+ *
+ * Unlike type_register_static(), this call does not require @info or it's
+ * string members to continue to exist after the call returns.
+ *
+ * Returns: 0 on failure, the new #Type on success.
+ */
+Type type_register(const TypeInfo *info);
+
+/**
+ * object_class_dynamic_cast_assert:
+ * @klass: The #ObjectClass to attempt to cast.
+ * @typename: The QOM typename of the class to cast to.
+ *
+ * Returns: This function always returns @klass and asserts on failure.
+ */
+ObjectClass *object_class_dynamic_cast_assert(ObjectClass *klass,
+ const char *typename);
+
+ObjectClass *object_class_dynamic_cast(ObjectClass *klass,
+ const char *typename);
+
+/**
+ * object_class_get_name:
+ * @klass: The class to obtain the QOM typename for.
+ *
+ * Returns: The QOM typename for @klass.
+ */
+const char *object_class_get_name(ObjectClass *klass);
+
+ObjectClass *object_class_by_name(const char *typename);
+
+void object_class_foreach(void (*fn)(ObjectClass *klass, void *opaque),
+ void *opaque);
+
+#endif
diff --git a/qom/Makefile b/qom/Makefile
new file mode 100644
index 0000000000..a3c789207e
--- /dev/null
+++ b/qom/Makefile
@@ -0,0 +1 @@
+qom-y = object.o
diff --git a/qom/object.c b/qom/object.c
new file mode 100644
index 0000000000..ef37e080d4
--- /dev/null
+++ b/qom/object.c
@@ -0,0 +1,485 @@
+/*
+ * QEMU Object Model
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.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 "qemu/object.h"
+#include "qemu-common.h"
+
+#define MAX_INTERFACES 32
+
+typedef struct InterfaceImpl InterfaceImpl;
+typedef struct TypeImpl TypeImpl;
+
+struct InterfaceImpl
+{
+ const char *parent;
+ void (*interface_initfn)(ObjectClass *class, void *data);
+ TypeImpl *type;
+};
+
+struct TypeImpl
+{
+ const char *name;
+
+ size_t class_size;
+
+ size_t instance_size;
+
+ void (*class_init)(ObjectClass *klass, void *data);
+ void (*class_finalize)(ObjectClass *klass, void *data);
+
+ void *class_data;
+
+ void (*instance_init)(Object *obj);
+ void (*instance_finalize)(Object *obj);
+
+ bool abstract;
+
+ const char *parent;
+ TypeImpl *parent_type;
+
+ ObjectClass *class;
+
+ int num_interfaces;
+ InterfaceImpl interfaces[MAX_INTERFACES];
+};
+
+typedef struct Interface
+{
+ Object parent;
+ Object *obj;
+} Interface;
+
+#define INTERFACE(obj) OBJECT_CHECK(Interface, obj, TYPE_INTERFACE)
+
+static GHashTable *type_table_get(void)
+{
+ static GHashTable *type_table;
+
+ if (type_table == NULL) {
+ type_table = g_hash_table_new(g_str_hash, g_str_equal);
+ }
+
+ return type_table;
+}
+
+static void type_table_add(TypeImpl *ti)
+{
+ g_hash_table_insert(type_table_get(), (void *)ti->name, ti);
+}
+
+static TypeImpl *type_table_lookup(const char *name)
+{
+ return g_hash_table_lookup(type_table_get(), name);
+}
+
+TypeImpl *type_register(const TypeInfo *info)
+{
+ TypeImpl *ti = g_malloc0(sizeof(*ti));
+
+ g_assert(info->name != NULL);
+
+ ti->name = g_strdup(info->name);
+ ti->parent = g_strdup(info->parent);
+
+ ti->class_size = info->class_size;
+ ti->instance_size = info->instance_size;
+
+ ti->class_init = info->class_init;
+ ti->class_finalize = info->class_finalize;
+ ti->class_data = info->class_data;
+
+ 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++;
+ }
+ }
+
+ type_table_add(ti);
+
+ return ti;
+}
+
+TypeImpl *type_register_static(const TypeInfo *info)
+{
+ return type_register(info);
+}
+
+static TypeImpl *type_get_by_name(const char *name)
+{
+ if (name == NULL) {
+ return NULL;
+ }
+
+ return type_table_lookup(name);
+}
+
+static TypeImpl *type_get_parent(TypeImpl *type)
+{
+ if (!type->parent_type && type->parent) {
+ type->parent_type = type_get_by_name(type->parent);
+ g_assert(type->parent_type != NULL);
+ }
+
+ return type->parent_type;
+}
+
+static bool type_has_parent(TypeImpl *type)
+{
+ return (type->parent != NULL);
+}
+
+static size_t type_class_get_size(TypeImpl *ti)
+{
+ if (ti->class_size) {
+ return ti->class_size;
+ }
+
+ if (type_has_parent(ti)) {
+ return type_class_get_size(type_get_parent(ti));
+ }
+
+ return sizeof(ObjectClass);
+}
+
+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,
+ };
+ char *name = g_strdup_printf("<%s::%s>", ti->name, iface->parent);
+
+ info.name = name;
+ iface->type = type_register(&info);
+ g_free(name);
+}
+
+static void type_class_init(TypeImpl *ti)
+{
+ size_t class_size = sizeof(ObjectClass);
+ int i;
+
+ if (ti->class) {
+ return;
+ }
+
+ ti->class_size = type_class_get_size(ti);
+
+ ti->class = g_malloc0(ti->class_size);
+ ti->class->type = ti;
+
+ if (type_has_parent(ti)) {
+ TypeImpl *parent = type_get_parent(ti);
+
+ type_class_init(parent);
+
+ class_size = parent->class_size;
+ g_assert(parent->class_size <= ti->class_size);
+
+ 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 (i = 0; i < ti->num_interfaces; i++) {
+ type_class_interface_init(ti, &ti->interfaces[i]);
+ }
+
+ if (ti->class_init) {
+ ti->class_init(ti->class, ti->class_data);
+ }
+}
+
+static void object_interface_init(Object *obj, InterfaceImpl *iface)
+{
+ TypeImpl *ti = iface->type;
+ Interface *iface_obj;
+
+ iface_obj = INTERFACE(object_new(ti->name));
+ iface_obj->obj = obj;
+
+ obj->interfaces = g_slist_prepend(obj->interfaces, iface_obj);
+}
+
+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);
+ }
+}
+
+void object_initialize_with_type(void *data, TypeImpl *type)
+{
+ Object *obj = data;
+
+ g_assert(type != NULL);
+ g_assert(type->instance_size >= sizeof(ObjectClass));
+
+ type_class_init(type);
+ g_assert(type->abstract == false);
+
+ memset(obj, 0, type->instance_size);
+ obj->class = type->class;
+ object_init_with_type(obj, type);
+}
+
+void object_initialize(void *data, const char *typename)
+{
+ TypeImpl *type = type_get_by_name(typename);
+
+ object_initialize_with_type(data, type);
+}
+
+static void object_deinit(Object *obj, TypeImpl *type)
+{
+ if (type->instance_finalize) {
+ 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));
+ }
+}
+
+void object_finalize(void *data)
+{
+ Object *obj = data;
+ TypeImpl *ti = obj->class->type;
+
+ object_deinit(obj, ti);
+}
+
+Object *object_new_with_type(Type type)
+{
+ Object *obj;
+
+ g_assert(type != NULL);
+
+ obj = g_malloc(type->instance_size);
+ object_initialize_with_type(obj, type);
+
+ return obj;
+}
+
+Object *object_new(const char *typename)
+{
+ TypeImpl *ti = type_get_by_name(typename);
+
+ return object_new_with_type(ti);
+}
+
+void object_delete(Object *obj)
+{
+ object_finalize(obj);
+ g_free(obj);
+}
+
+static bool object_is_type(Object *obj, const char *typename)
+{
+ TypeImpl *target_type = type_get_by_name(typename);
+ TypeImpl *type = obj->class->type;
+ GSList *i;
+
+ /* Check if typename is a direct ancestor of type */
+ while (type) {
+ if (type == target_type) {
+ return true;
+ }
+
+ type = type_get_parent(type);
+ }
+
+ /* 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), typename)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+Object *object_dynamic_cast(Object *obj, const char *typename)
+{
+ GSList *i;
+
+ /* Check if typename is a direct ancestor */
+ if (object_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 (object_is_type(OBJECT(iface), typename)) {
+ return OBJECT(iface);
+ }
+ }
+
+ /* Check if obj is an interface and its containing object is a direct
+ * ancestor of typename */
+ if (object_is_type(obj, TYPE_INTERFACE)) {
+ Interface *iface = INTERFACE(obj);
+
+ if (object_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);
+
+Object *object_dynamic_cast_assert(Object *obj, const char *typename)
+{
+ Object *inst;
+
+ inst = object_dynamic_cast(obj, typename);
+
+ if (!inst) {
+ fprintf(stderr, "Object %p is not an instance of type %s\n",
+ obj, typename);
+ abort();
+ }
+
+ return inst;
+}
+
+ObjectClass *object_class_dynamic_cast(ObjectClass *class,
+ const char *typename)
+{
+ TypeImpl *target_type = type_get_by_name(typename);
+ TypeImpl *type = class->type;
+
+ while (type) {
+ if (type == target_type) {
+ return class;
+ }
+
+ type = type_get_parent(type);
+ }
+
+ return NULL;
+}
+
+ObjectClass *object_class_dynamic_cast_assert(ObjectClass *class,
+ const char *typename)
+{
+ ObjectClass *ret = object_class_dynamic_cast(class, typename);
+
+ if (!ret) {
+ fprintf(stderr, "Object %p is not an instance of type %s\n",
+ class, typename);
+ abort();
+ }
+
+ return ret;
+}
+
+const char *object_get_typename(Object *obj)
+{
+ return obj->class->type->name;
+}
+
+ObjectClass *object_get_class(Object *obj)
+{
+ return obj->class;
+}
+
+const char *object_class_get_name(ObjectClass *klass)
+{
+ return klass->type->name;
+}
+
+ObjectClass *object_class_by_name(const char *typename)
+{
+ TypeImpl *type = type_get_by_name(typename);
+
+ if (!type) {
+ return NULL;
+ }
+
+ type_class_init(type);
+
+ return type->class;
+}
+
+typedef struct OCFData
+{
+ void (*fn)(ObjectClass *klass, void *opaque);
+ void *opaque;
+} OCFData;
+
+static void object_class_foreach_tramp(gpointer key, gpointer value,
+ gpointer opaque)
+{
+ OCFData *data = opaque;
+ TypeImpl *type = value;
+
+ type_class_init(type);
+
+ data->fn(value, type->class);
+}
+
+void object_class_foreach(void (*fn)(ObjectClass *klass, void *opaque),
+ void *opaque)
+{
+ OCFData data = { fn, opaque };
+
+ g_hash_table_foreach(type_table_get(), object_class_foreach_tramp, &data);
+}