目录
3.1 、类型注册1.2 对象创建1.3 对象获取1.4 属性操作1.5 类型转换
Qemu Object Model
QOM (Qemu Object Model)是Qemu实现的面向对象编程模式。Qemu是用C语言编写的,而C语言是面向过程的编程语言,无法享受面向对象编程模式针对复杂软件系统在设计模式上的优越性。为解决该问题,Qemu社区通过C语言实现了一套面向对象的编程接口,即QOM,并成功将其应用在Qemu设备模型的管理中。
1、简介
QOM是一套创建“类”和“对象”的编程接口。这套接口也是一种支持用户创建类型并根据类型实例化对象的灵活框架,其具有以下特性:
支持动态注册并创建类型;
支持类型的单继承(仅有一个父类);
支持类型的多继承;
2、 一个简单应用实例
下面通过一个简单代码实例,先来了解QOM的基本使用方法。
#include "qdev.h"
#define TYPE_MY_DEVICE "my-device"
// No new virtual functions: we can reuse the typedef for the
// superclass.
typedef DeviceClass MyDeviceClass;
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)
这个代码示例的功能是通过QOM接口(type_init, type_register_static)向QOM系统注册了一个TYPE_MY_DEVICE类型。该类型包含一个class类(结构) MyDeviceClass和一个object类(结构)MyDevice。class类包括一组函数指针,用来灵活指明调用函数;object类通常用来表达对象的属性信息。一个class类仅会实例化出一个class对象,而object类可以实例化出多个对象且每个对象都指向同一个class对象,如图1所示。其中ObjectClass和Object为QOM定义的基本结构,DeviceClass和DeviceState是Qemu为设备模型定义的基本结构。
图1. 示例类与对象关系图
从这个示例中还可以看出类型TYPE_MY_DEVICE的父类型是TYPE_DEVICE (见my_device_info中的parent字段),但是实际的父子关系是在具体的类型定义中体现的,如MyDevice中的第一个字段parent即是DeviceState类,MyDeviceClass和DeviceClass为同一结构。
3、QOM接口基本用法
总的来说,QOM提供的接口可分为五类:类型注册、对象创建、对象获取、属性操作和类型转换。
回到顶部3.1 、类型注册
TypeImpl type_register_static(const TypeInfo info);
该接口向QOM系统注册了一个由TypeInfo描述的类型。
struct TypeInfo{
const char name; //表示该类型的字符串名称;
const char parent; //表示该类型的父类型的字符串名称;
size_t instance_size; //该类型所能创建的object类对象的内存空间占用大小;如果该值为0,则使用父类的instance_size;
void (instance_init)(Object obj);//创建的object类对象的初始化函数;仅初始化该类型自身的成员属性,不包含父类型成员(通常父类型已经初始化完成);
void (instance_finalize)(Object obj);//创建的object类对象的析构函数;
bool abstract;//表示该类型是否为抽象类;抽象类不能实例化object类对象;
size_t class_size;//该类型所能创建的class类对象的内存空间占用大小;如果该值为0,则使用父类型的class_size;
void (class_init)(ObjectClass klass, void data);//创建的class类对象的初始化函数;仅初始化该类型自身的函数指针,不包含父类;
void (class_base_init)(ObjectClass klass, void data);//该函数在父类型的class类对象初始化完成后,在当前class类对象的class_init执行前被调用;
void (class_finalize)(ObjectClass klass, void data);//创建的class类对象的析构函数;
void class_data;//传递给class_init、class_base_init和class_finalize的参数;
InterfaceInfo interfaces;//该类型的接口列表;
};
回到顶部1.2 对象创建
Object object_new(const char typename);
该接口创建一个类型名为typename的object类对象。创建过程中,如果该类型对应的class类对象不存在,还会创建该class类对象并调用其class_init初始化;如果存在父类型,还会递归创建父类的class类对象并初始化。
Class类对象创建完成后,还会对当前object类对象执行父类和自身的instance_init函数。最终,对象初始化完成后,其引用计数为1。
Object object_new_with_type(Type type);
该接口功能同object_new,参数由字符名改为Type。
void object_initialize(void obj, const char typename);
该接口对已经存在的对象obj,按typename类型进行初始化操作。
Object object_dynamic_cast(Object obj, const char typename);
该接口将已经存在的对象obj强转成typename类型。
回到顶部1.3 对象获取
ObjectClass object_get_class(Object obj);
该接口获取obj对象的唯一class类对象。
const char object_get_typename(Object obj);
该接口获取obj对象的字符串类型名。
ObjectClass object_class_get_parent(ObjectClass klass);
该接口获取class对象klass的父类的class对象。
const char object_class_get_name(ObjectClass klass);
该接口获取class对象klass对应的类型的字符串名称
回到顶部1.4 属性操作
void object_property_add(Object //代码效果参考:http://www.jhylw.com.cn/100631107.html
obj, const char name, const char type,ObjectPropertyAccessor get,
ObjectPropertyAccessor set,
ObjectPropertyRelease release,
void opaque, struct Error errp);
void object_property_del(Object obj, const char name, struct Error errp);
ObjectProperty object_property_find(Object obj, const char name,
struct Error **errp);
void object_property_get(Object obj, struct Visitor v, const char name,
struct Error errp);
void object_property_set(Object obj, struct Visitor v, const char *name,
struct Error errp);
void object_property_set_str(Object obj, const char value,
const //代码效果参考:http://www.jhylw.com.cn/570832983.html
char name, struct Error **errp);char object_property_get_str(Object obj, const char name,
struct Error errp);
void object_property_set_link(Object obj, Object value,
const char *name, struct Error errp);
Object object_property_get_link(Object obj, const char name,
struct Error **errp);
void object_property_set_bool(Object obj, bool value,
const char name, struct Error **errp);
bool object_property_get_bool(Object obj, const char name,
struct Error **errp);
void object_property_set_int(Object obj, int64_t value,
const char name, struct Error **errp);
int64_t object_property_get_int(Object obj, const char name,
struct Error **errp);
void object_property_add_child(Object obj, const char name,
Object child, struct Error errp);
void object_property_add_link(Object obj, const char name,
const char *type, Object child,
struct Error errp);
回到顶部1.5 类型转换
#define OBJECT_CHECK(type, obj, name) \
((type )object_dynamic_cast_assert(OBJECT(obj), (name), \
FILE, LINE, func))
该宏将obj强转成type类型。
#define OBJECT_CLASS_CHECK(class, obj, name) \
((class )object_class_dynamic_cast_assert(OBJECT_CLASS(obj), (name), \
FILE, LINE, func))
该宏将obj强转成对应的class类对象。
4、Qemu设备模型
5、QOM设备初始化调用流程(virtio-balloon为例)
6. 数据结构组成:
7. QEMU侧QOM模型结构
8. 一个自建设备的初始化流程
1. 存储init执行函数
在main_impl执行之前,通过type_init将设备init执行函数存入全局数组init_type_listQOMQOMQOM,调用关系如下,参考流程图①:
c</p> <p>register_module_init(mydevice_register_types)</p> <p>->find_type(init_type_list【QOM】)->INSERT</p> <p>
2. 存储TypeInfo
main_impl中执行module_call_init, 遍历init_type_list中注册的QOM类型设备的执行函数,将TypeInfo转换为TypeImpl存储到全局hash表type_table。调用关系如下,参考流程图②:
c</p> <p>module_call_init(QOM) -> mydevice_register_types -> type_register_static -> type_table_add(TypeInfo->TypeImpl) -> g_hash_table_insert(type_table)</p> <p>
3. class初始化
在查找主板时,提前对所有设备的class进行了初始化,调用关系如下,参考流程图③:
c</p> <p>select_machine -> find_default_machine -> object_class_foreach(type_table) -> object_class_foreach_tramp -> type_initialize(ti) -> ti->class_init -> mydevice_class_init</p> <p>
4. instance初始化
main_impl中执行设备初始化时,会遍历所有添加到命令参数-device中的设备,新设备在此将完成实例化创建。调用关系如下,参考流程图④:
c</p> <p>qemu_opts_foreach(device) -> device_init_func -> qdev_device_add -> object_new(my-device) -> object_new_with_type(ti) -> object_initialize_with_type(ti) -> ti->instance_init -> mydevice_instance_init</p> <p>
5. 设备实例化
当设备固有属性初始化完成后,将进行设备的创建操作,对应操作仍在qdev_device_add中,在object_new完成后执行。设备创建通过qdev的realize体系完成,在instance_init环节中qdev注册了realize属性,设备创建将通过realize属性置true**来实现。调用关系如下,参考流程图⑤:
c</p> <p>qdev_device_add -> object_property_set_bool(realize) -> device_set_realized -> dc->realize -> mydevice_realize</p> <p>
此处需要注意,先前在class_init中修改了父设备的realize执行函数,因此此处dc->realize将指向我们自己定义的函数