接前一篇文章:QEMU源码全解析12 —— QOM介绍(1)
本文内容参考:
《趣谈Linux操作系统》 —— 刘超,极客时间
《QEMU/KVM》源码解析与应用 —— 李强,机械工业出版社
特此致谢!
本回开始对QOM涉及的各个方面进行深入细致的解析。
1. 类型的注册
在面向对象思想中,说到对象时,都会提到它所属的类。QEMU也需要实现一个类型系统。以hw/misc/edu.c文件为例(前文是以accel/kvm/kvm-all.c为例),这本身不是一个实际的设备,而是教学用的设备,其结构简单,比较清楚地展示了QEMU中的模拟设备。类型的注册是通过type_init完成的。代码如下:
static void pci_edu_register_types(void)
{
    static InterfaceInfo interfaces[] = {
        { INTERFACE_CONVENTIONAL_PCI_DEVICE },
        { },
    };
    static const TypeInfo edu_info = {
        .name          = TYPE_PCI_EDU_DEVICE,
        .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)在include/qemu/module.h中可以看到,type_init是一个宏(实际上前文已讲过,但此处是从QOM的角度再讲一次,算作是一次回顾和巩固吧,下同),并且除了type_init,还有其它几个init宏,如block_init、opts_init、trace_init等,在include/qemu/module.h中,如下所示:
#define block_init(function) module_init(function, MODULE_INIT_BLOCK)
#define opts_init(function) module_init(function, MODULE_INIT_OPTS)
#define type_init(function) module_init(function, MODULE_INIT_QOM)
#define trace_init(function) module_init(function, MODULE_INIT_TRACE)
#define xen_backend_init(function) module_init(function, \
                                               MODULE_INIT_XEN_BACKEND)
#define libqos_init(function) module_init(function, MODULE_INIT_LIBQOS)
#define fuzz_target_init(function) module_init(function, \
                                               MODULE_INIT_FUZZ_TARGET)每一个宏定义都表示一类module,均通过module_init按照不同的参数构造出来。前文已给出过module_init的代码,为了便于理解和回顾,再次贴出代码,在同文件(include/qemu/module.h)中,如下所示:
#ifdef BUILD_DSO
void DSO_STAMP_FUN(void);
/* This is a dummy symbol to identify a loaded DSO as a QEMU module, so we can
 * distinguish "version mismatch" from "not a QEMU module", when the stamp
 * check fails during module loading */
void qemu_module_dummy(void);
#define module_init(function, type)                                         \
static void __attribute__((constructor)) do_qemu_init_ ## function(void)    \
{                                                                           \
    register_dso_module_init(function, type);                               \
}
#else
/* This should not be used directly.  Use block_init etc. instead.  */
#define module_init(function, type)                                         \
static void __attribute__((constructor)) do_qemu_init_ ## function(void)    \
{                                                                           \
    register_module_init(function, type);                                   \
}
#endif根据是否定义了BUILD_DSO宏,module_init有不同的定义,这里假设未定义该宏,则module_init的定义如下(前文也是这么讲的):
/* This should not be used directly.  Use block_init etc. instead.  */
#define module_init(function, type)                                         \
static void __attribute__((constructor)) do_qemu_init_ ## function(void)    \
{                                                                           \
    register_module_init(function, type);                                   \
}可以看到各个QOM类型都是通过register_module_init函数注册到了系统。其中function是每个类型独立的,即每个类型都需要自行单独实现的初始化函数。type是MODULE_INIT_QOM。这里的constructor是编译器属性,编译器会把带有这个属性的函数do_qemu_init_ ## function放到特殊的段中,带有这个属性的函数会早于主函数main()执行,也就是说所有的QOM类型注册在main执行之前就已经执行了。register_module_init及相关函数代码如下(util/module.c中):
static ModuleTypeList *find_type(module_init_type type)
{
    init_lists();
    return &init_type_list[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);
}register_module_init函数以类型的初始化函数(第1个参数void (*fn)(void))及所属类型(第2个参数type,对于QOM类型来说是MODULE_INIT_QOM)构建出一个ModuleEntry,然后插入到对应的module(对于QOM来说是MODULE_INIT_QOM这个module)所属的链表中。所有module的链表存放在一个init_type_list数组中。init_type_list与各个module以及ModuleEntry之间的关系简图如下所示:

综上可知,QEMU使用的各个类型在main函数执行之前就统一注册到了init_type_list[MODULE_INIT_QOM]这个链表中。
欲知后事如何,且看下回分解。













![[数据库]对数据库事务进行总结](https://img-blog.csdnimg.cn/84a35a874e954e4da9d0050ba933d31b.png)





