qemu2的qom系统分析(-)对象系统

前边分析machine的注册和选择,发现如果 不了解qom系统是很难分析的。
qom系统的说明在include/qom/object.h中。看注释估计是个中国人写的

系统用于创建新的类型和对象,也就是我们在面向对象系统里面说的class,和object, 另外系统还实现了接口继承(可以多继承)。

下面我们来看下qom这个面向对象系统是如何实现的。

首先我们来剖析下面向对象系统的特点。
首先面向对象系统把方法和数据组成一个结构,叫类(class), 类描述的信息有两种
1 数据
2 方法
如何把数据于方法关联起来了,最好的办法就是传参,面向对象语言于面向过程语言的的区别在于方法是不是属于类,其实面向过程也可以实现面向对象,例如下面的例子

class MyClass {
public:
   int a;
   void setA(int a){
       this->a = a;
   }
}

要想用面向过程的语言实现上面的类似面向对象功能该如何写呢,如下

typedefine struct MyClass {
int a ;
void (*setA)(MyClass *this, int a);
} MyClass

MyClass myclass;

void setA(MyClass *this, int a) {
    this->a = a;
}

myclass.setA = setA;

所以我们要想用c实现一个面向对象的系统,我们需要做到如下几点
1 对于一个class,我们要知道它的具体方法实现,如 MyClass我们要知道它的setA指向哪里。只有这样我们创建的每一个实例才行为一致。
2 对于多态呢 还要保证函数指针的如setA函数的第一个参数必须满足
是MyClass或者MyClass的子类
3 另外对于接口的实现还要保证可以多继承,其实最主要的功能是能将实现类转化为接口。

好了 大概理清了思路,我们就来分析下qom是如何实现的
我们先不管接口实现,先来看看class绑定方法是如何实现的

typedef void (*DeviceReset)(DeviceState *dev);

typedefine  struct DeviceClass {
     ObjectClass parent_class;
     DeviceReset reset; 
}
  void my_device_class_init(ObjectClass *klass, void *class_data)
  {
      DeviceClass *dc = DEVICE_CLASS(klass);
      dc->reset = my_device_reset;
  }
 
  static const TypeInfo my_device_info = {
      .name = TYPE_MY_DEVICE,
      .parent = TYPE_DEVICE,
      .instance_size = sizeof(MyDevice),
      .class_init = my_device_class_init,
  };
  static void my_device_register_types(void)
  {
      type_register_static(&my_device_info);
  }
 
  type_init(my_device_register_types)

如上type_register_static会将类型注册到类型系统。TypeInfo的class_init的实现为my_device_class_init,从名字可以该处开函数为class初始化的,在这个函数中会将我们的类DeviceClass的成员函数绑定为my_device_reset(用户实现的函数,从而把类方法进行绑定)。
细心的用户还可能注意到DeviceReset的第一个参数为DeviceState,在qom里面确实习惯将一个class的实例写作xxxstate。对于静态函数当然参数应该为xxxclass

看到了方法绑定我们再来分析下如何实现继承。
前面的例子又是细心的读者应该注意到DeviceClass的第一个成员函数为 ObjectClass parent_class, 没错ObjectClass就是它的父类。

我们再来举个例子

struct PCMachineClass {
    MachineClass parent_class;
    ......
  }
  struct MachineClass {
    ObjectClass parent_class;
    .......
  }

可以看到PCMachineClass继承MachineClass,而MachineClass又继承PCMachineClass,这样就好理解了吧,怎么理解呢,PCMachineClass如何覆盖MachineClass和使用MachineClass的函数呢?object.h的例子里也是有答案的

 * typedef struct MyState MyState;
 *
 * typedef void (*MyDoSomething)(MyState *obj);
 *
 * typedef struct MyClass {
 *     ObjectClass parent_class;
 *
 *     MyDoSomething do_something;
 * } MyClass;
 *
 * static void my_do_something(MyState *obj)
 * {
 *     // do something
 * }
 *
 * static void my_class_init(ObjectClass *oc, void *data)
 * {
 *     MyClass *mc = MY_CLASS(oc);
 *
 *     mc->do_something = my_do_something;
 * }
 *
 * static const TypeInfo my_type_info = {
 *     .name = TYPE_MY,
 *     .parent = TYPE_OBJECT,
 *     .instance_size = sizeof(MyState),
 *     .class_size = sizeof(MyClass),
 *     .class_init = my_class_init,
 * };
 *
 * typedef struct DerivedClass {
 *     MyClass parent_class;
 *
 *     MyDoSomething parent_do_something;
 * } DerivedClass;
 *
 * static void derived_do_something(MyState *obj)
 * {
 *     DerivedClass *dc = DERIVED_GET_CLASS(obj);
 *
 *     // do something here
 *     dc->parent_do_something(obj);
 *     // do something else here
 * }
 *
 * static void derived_class_init(ObjectClass *oc, void *data)
 * {
 *     MyClass *mc = MY_CLASS(oc);
 *     DerivedClass *dc = DERIVED_CLASS(oc);
 *
 *     dc->parent_do_something = mc->do_something;
 *     mc->do_something = derived_do_something;
 * }
 *
 * static const TypeInfo derived_type_info = {
 *     .name = TYPE_DERIVED,
 *     .parent = TYPE_MY,
 *     .class_size = sizeof(DerivedClass),
 *     .class_init = derived_class_init,
 * };

由于父class的数据结构在子class的第一个结构体变量,所以可以将子class直接强制转换为父class。 所以可以在子class_init的时候给父class的成员函数赋值, 这样就实现了多态和抽象类的功能,还可以在子class调用父class的函数。

可想而知,在子class初始化的时候需要执行父class的初始化,然后将父class的数据直接memcpy到子class的parent_class数据域里面。多态的基本功能就算完成了。
所以class_init的函数原型为

    void (*class_init)(ObjectClass *klass, void *data);
第一个参数为ObjectClass,这就是c语言里面的多态实现方式吧,很有意思

下面在看看看如何创建实例

* #include "qdev.h"
 *
 * #define TYPE_MY_DEVICE "my-device"
 *
 * // No new virtual functions: we can reuse the typedef for the
 * // superclass.
 * typedef DeviceClass MyDeviceClass;
 * struct DeviceState {
    /*< private >*/
    Object parent_obj;
    ...
    }
 * typedef struct MyDevice
 * {
 *     DeviceState parent;
 *
 *     int reg0, reg1, reg2;
 * } MyDevice;
 *
 * static const TypeInfo my_device_info = {
 *     .name = TYPE_MY_DEVICE,
 *     .parent = TYPE_DEVICE,
 *     .instance_size = sizeof(MyDevice),
 * };
 *
 * static void my_device_register_types(void)
 * {
 *     type_register_static(&my_device_info);
 * }
 *
 * type_init(my_device_register_types)
 *   </programlisting>
 * </example>
 *
struct Object
{
    /*< private >*/
    ObjectClass *clazz;
    ObjectFree *free;
    GHashTable *properties;
    uint32_t ref;
    Object *parent;
};

其实也是类似上面class的多态形式,通过第一个参数Object* 将数据可以转化成对应的父类实例和子类实例,通过Object又可以找到对应的class,通过object的parent又可以找到该类的父类。

那么如何实现接口继承呢? 这是一种多继承的方式。

这个分析起来还是有些费劲的。

我们先来看看ObjectClass的定义,这是所有Class类型的基础

/**
 * ObjectClass:
 *
 * The base for all classes.  The only thing that #ObjectClass contains is an
 * integer type handle.
 */
struct ObjectClass
{
    /*< private >*/
    Type type;
    GSList *interfaces;

    const char *object_cast_cache[OBJECT_CLASS_CAST_CACHE];
    const char *class_cast_cache[OBJECT_CLASS_CAST_CACHE];

    ObjectUnparent *unparent;

    GHashTable *properties;
};

其中interfaces 则代表该类实现的接口,这里需要注意,接口是无状态的,也就是只有函数没有数据。所以这里不想抽象类,子类不但继承了状态,还可能覆盖了方法,这里接口只不过是强调一种关系,所以接口更重要的是明确这种关系。
我们来举个例子如何实现接口

typedef struct HotplugHandlerClass {
    /* <private> */
    InterfaceClass parent;

    /* <public> */
    hotplug_fn pre_plug;
    hotplug_fn plug;
    hotplug_fn unplug_request;
    hotplug_fn unplug;
} HotplugHandlerClass;
/**
 * 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;
    /*< private >*/
    ObjectClass *concrete_class;
};
typedef void (*hotplug_fn)(HotplugHandler *plug_handler,
                           DeviceState *plugged_dev, Error **errp);

HotplugHandlerClass的类型为一个接口,接口的实现描述了一种关系,parent_class为接口的类型,concrete_class则为实现接口的类型
HotplugHandlerClass为一个接口,下面有四个函数指针。
我们来找一个随便的实现了HotplugHandlerClass 看它如何实现接口

static void pc_machine_class_init(ObjectClass *oc, void *data)
{
    MachineClass *mc = MACHINE_CLASS(oc);
    HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);

 ......
    hc->pre_plug = pc_machine_device_pre_plug_cb;
    hc->plug = pc_machine_device_plug_cb;
    hc->unplug_request = pc_machine_device_unplug_request_cb;
    hc->unplug = pc_machine_device_unplug_cb;
    ......
}

这个方法是PCMachineClass类的初始化方法,做了一些省略,这里可以看出,使用 HOTPLUG_HANDLER_CLASS将参数ObjectClass *oc,转化成了HotplugHandlerClass接口,这是我们突破的关键,是怎么将一个ObjectClass转化为一个接口的呢?
答案就在这个宏里面

#define TYPE_HOTPLUG_HANDLER "hotplug-handler"
#define HOTPLUG_HANDLER_CLASS(klass) \
     OBJECT_CLASS_CHECK(HotplugHandlerClass, (klass), TYPE_HOTPLUG_HANDLER)

#define OBJECT_CLASS(class) \
    ((ObjectClass *)(class))

#define OBJECT_CLASS_CHECK(class_type, class, name) \
    ((class_type *)object_class_dynamic_cast_assert(OBJECT_CLASS(class), (name), \
                                               __FILE__, __LINE__, __func__))

完全展开如下

((class_type *)object_class_dynamic_cast_assert(((*ObjectClasss) oc), ("hotplug-handler"),   __FILE__, __LINE__, __func__))

object_class_dynamic_cast_assert的实现如下

ObjectClass *object_class_dynamic_cast_assert(ObjectClass *class,
                                              const char *typename,
                                              const char *file, int line,
                                              const char *func)
{
    ObjectClass *ret;

    if (!class || !class->interfaces) {
        return class;
    }

    ret = object_class_dynamic_cast(class, typename);
    if (!ret && class) {
        fprintf(stderr, "%s:%d:%s: Object %p is not an instance of type %s\n",
                file, line, func, class, typename);
        abort();
    }
    return ret;
}

ObjectClass *object_class_dynamic_cast(ObjectClass *class,
                                       const char *typename)
{
    ObjectClass *ret = NULL;
    TypeImpl *target_type;
    TypeImpl *type;

    if (!class) {
        return NULL;
    }

    /* A simple fast path that can trigger a lot for leaf classes.  */
    type = class->type;
    if (type->name == typename) {
        return class;
    }

    target_type = type_get_by_name(typename);
    if (!target_type) {
        /* target class type unknown, so fail the cast */
        return NULL;
    }

    if (type->clazz->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++;
            }
         }

        /* 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 ret;
}

主要实现就在object_class_dynamic_cast中了,主要就是type_is_ancestor这个函数了,对于typename对应的类型为非接口的情况,就是判断target_type是否为type的父类

对于target_type类型为接口的情况下,遍历class所实现的接口,如果实现的接口是typename对应接口的子类,则可以直接转化返回接口。

到这里我们可以推测,如果一个类实现了接口,则会在自己的 class->interfaces里面添加该接口的一个子类实现。

这些代码的实现就在type_initialize中

static void type_initialize(TypeImpl *ti)
{
    TypeImpl *parent;

    if (ti->clazz) {
        return;
    }

    ti->class_size = type_class_get_size(ti);
    ti->instance_size = type_object_get_size(ti);
    /* Any type with zero instance_size is implicitly abstract.
     * This means interface types are all abstract.
     */
    if (ti->instance_size == 0) {
        ti->abstract = true;
    }

    ti->clazz = g_malloc0(ti->class_size);

    parent = type_get_parent(ti);
    if (parent) {
        type_initialize(parent);
        GSList *e;
        int i;

        g_assert_cmpint(parent->class_size, <=, ti->class_size);
        memcpy(ti->clazz, parent->clazz, parent->class_size);
        ti->clazz->interfaces = NULL;
        ti->clazz->properties = g_hash_table_new_full(
            g_str_hash, g_str_equal, g_free, object_property_free);

        for (e = parent->clazz->interfaces; e; e = e->next) {
            InterfaceClass *iface = e->data;
            ObjectClass *klass = OBJECT_CLASS(iface);

            type_initialize_interface(ti, iface->interface_type, klass->type);
        }

        for (i = 0; i < ti->num_interfaces; i++) {
            TypeImpl *t = type_get_by_name(ti->interfaces[i].typename);
            for (e = ti->clazz->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, t, t);
        }
    } else {
        ti->clazz->properties = g_hash_table_new_full(
            g_str_hash, g_str_equal, g_free, object_property_free);
    }

    ti->clazz->type = ti;

    while (parent) {
        if (parent->class_base_init) {
            parent->class_base_init(ti->clazz, ti->class_data);
        }
        parent = type_get_parent(parent);
    }

    if (ti->class_init) {
        ti->class_init(ti->clazz, ti->class_data);
    }
}

static void type_initialize_interface(TypeImpl *ti, TypeImpl *interface_type,
                                      TypeImpl *parent_type)
{
    InterfaceClass *new_iface;
    TypeInfo info = { };
    TypeImpl *iface_impl;

    info.parent = parent_type->name;
    info.name = g_strdup_printf("%s::%s", ti->name, interface_type->name);
    info.abstract = true;

    iface_impl = type_new(&info);
    iface_impl->parent_type = parent_type;
    type_initialize(iface_impl);
    g_free((char *)info.name);

    new_iface = (InterfaceClass *)iface_impl->clazz;
    new_iface->concrete_class = ti->clazz;
    new_iface->interface_type = interface_type;

    ti->clazz->interfaces = g_slist_append(ti->clazz->interfaces,
                                           iface_impl->clazz);
}

这里可以看出,子类会继承父类的所有接口,另外子类的接口会重新创建interface,他的concrete_class指向interface,他的parent_type指向父类对该接口创建的class

举个例子

struct MyHandler {
     InterfaceClass parent;
     void (*setA) ()
}

struct MyDevice {
    ObjectClass parent;
}

struct MyDeviceChild{
    MyDevice parent;
}

类似这样,MyDevice实现了 MyHandler

发布了113 篇原创文章 · 获赞 22 · 访问量 9万+

猜你喜欢

转载自blog.csdn.net/woai110120130/article/details/99179161
今日推荐