QOM模型初始化流程
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 *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 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. 一个自建设备的初始化流程
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了