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