QEMU中的QOM(1)

qemu中为了模拟各种虚拟设备和总线,采用了面向对象的思想,即QOM(QEMU Object Module).实现了封装、继承、多态的特性。可以放置虚拟设备相同功能的重复开发。QOM整个运作包括3个部分,即类型的注册、类型的初始化以及对象的初始化。
QOM对象机制组成部分

类型的注册

首先,介绍4种结构类型TypeInfo,TypeImpl,ObjectClass,Object。其中TypeInfo和TypeImpl主要用来保存类和对象的一些信息,ObjectClass是所有类的基类,Object是所有类的父类。

struct TypeInfo
{
    const char *name; //类型的名字
    const char *parent;//类型的父类类型名

    size_t instance_size;//object的大小(派生自Object),如果为0,则为父对象的大小
    void (*instance_init)(Object *obj);//初始化一个object时调用,父类已经初始化完成,只响应自己的成员
    void (*instance_post_init)(Object *obj);//结束一个object的初始化时调用,
    void (*instance_finalize)(Object *obj);//当销毁一个object时调用该函数,在父类调用@instance_finalize之前调用

    bool abstract;//如果该值为真,则类被认为是抽象类,不能直接实例化
    size_t class_size;//类的大小(派生自ObjectClass),

    void (*class_init)(ObjectClass *klass, void *data);//类初始化时发生
    void (*class_base_init)(ObjectClass *klass, void *data);//基类初始化完成,该类初始化之前发生
    void (*class_finalize)(ObjectClass *klass, void *data);//类销毁时发生
    void *class_data;//传递到上面3个函数的参数

    InterfaceInfo *interfaces;//指向一个static数组,该数组开始由0填充,
};

TypeImpl和TypeInfo的结构差不多,其实TypeInfo就是用来实例化TypeImpl的

struct TypeImpl
{
    const char *name;

    size_t class_size;

    size_t instance_size;

    void (*class_init)(ObjectClass *klass, void *data);
    void (*class_base_init)(ObjectClass *klass, void *data);
    void (*class_finalize)(ObjectClass *klass, void *data);

    void *class_data;

    void (*instance_init)(Object *obj);
    void (*instance_post_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];
};

ObjectClass是所有类的基类,包含的主要是一个整数type 句柄.

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;
};

Object是所有对象的基类,首个元素是一个指向ObjectClass的指针,由于C保证结构的第一个成员总是从该结构的字节0开始,只要任何自对象放置它的父类作为第一个成员,可以直接强转为#Object.因此,#Object包含一个对象类型的引用作为其第一个成员.允许在运行是识别对象的真实类型.

struct Object
{
    /*< private >*/
    ObjectClass *class;
    ObjectFree *free;
    GHashTable *properties;
    uint32_t ref;
    Object *parent;
};

以hw/misc/edu.c设备为例,先实例化了一个TypeInfo,并对属性进行了赋值,随后调用了type_register_static对TypeInfo进行注册.该函数的作用就是由TypeInfo生成一个TypeImpl实例,并以name为Key,以TypeInfo的实例为value存入一个hash表中.

static void pci_edu_register_types(void)
{
    static InterfaceInfo interfaces[] = {
        { INTERFACE_CONVENTIONAL_PCI_DEVICE },
        { },
    };
    static const TypeInfo edu_info = {
        .name          = "edu",
        .parent        = TYPE_PCI_DEVICE,
        .instance_size = sizeof(EduState),
        .instance_init = edu_instance_init,
        .class_init    = edu_class_init,
        .interfaces = interfaces,
    };

    type_register_static(&edu_info);
}
type_init(pci_edu_register_types)

TypeImpl *type_register_static(const TypeInfo *info)
{
    return type_register(info);
}
TypeImpl *type_register(const TypeInfo *info)
{
    assert(info->parent);
    return type_register_internal(info);
}
static TypeImpl *type_register_internal(const TypeInfo *info)
{
    TypeImpl *ti;
    ti = type_new(info);

    type_table_add(ti);
    return ti;
}
static TypeImpl *type_new(const TypeInfo *info)
{
    TypeImpl *ti = g_malloc0(sizeof(*ti));
    int i;

    g_assert(info->name != NULL);

    if (type_table_lookup(info->name) != NULL) {
        fprintf(stderr, "Registering `%s' which already exists\n", info->name);
        abort();
    }

    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_base_init = info->class_base_init;
    ti->class_finalize = info->class_finalize;
    ti->class_data = info->class_data;

    ti->instance_init = info->instance_init;
    ti->instance_post_init = info->instance_post_init;
    ti->instance_finalize = info->instance_finalize;

    ti->abstract = info->abstract;

    for (i = 0; info->interfaces && info->interfaces[i].type; i++) {
        ti->interfaces[i].typename = g_strdup(info->interfaces[i].type);
    }
    ti->num_interfaces = i;

    return ti;
}
static void type_table_add(TypeImpl *ti)
{
    assert(!enumerating_types);
    g_hash_table_insert(type_table_get(), (void *)ti->name, ti);
}

type_init是一个宏,其定义在include/qemu/module.h中,module_init也是一个宏,constructor是一个函数属性,告诉编译器在main执行之前执行.type可以在module.h中发现,主要有4种类型,MODULE_INIT_BLOCK,MODULE_INIT_OPTS,MODULE_INIT_QOM,MODULE_INIT_TRACE,每一种module都有一个MouduleTypeList链表.其实例始终指向链尾元素,替换后如下.

typedef struct{
        ModuleEntry*tqh_first;
        ModuleEntry** tqh_firsh;
} ModuleTypeList;
typedef struct ModuleEntry
{
  void (*init) (void);
  struct{
       ModuleEntry*tqh_first;
       ModuleEntry**tqh_firsh;
  }node;
  module_init_type type;
}ModuleEntry;


最后把ModuleEntry插入到对应module的ModuleTypeList中.自此就把pci_edu_register_types注册完成了

#define type_init(function) module_init(function, MODULE_INIT_QOM)

#define module_init(function, type)                                         \
static void __attribute__((constructor)) do_qemu_init_ ## function(void)    \
{                                                                           \
    register_module_init(function, type);                                   \
}
void register_module_init(void (*fn)(void), module_init_type type)
{
    ModuleEntry *e;
    ModuleTypeList *l;

    e = g_malloc0(sizeof(*e));
    e->init = fn;
    e->type = type;

    l = find_type(type);

    QTAILQ_INSERT_TAIL(l, e, node);
}
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值