接前一篇文章: QEMU源码全解析 —— 块设备虚拟化(5)
本文内容参考:
《趣谈Linux操作系统》 —— 刘超,极客时间
《QEMU/KVM源码解析与应用》 —— 李强,机械工业出版社
特此致谢!
QEMU初始化阶段的块设备虚拟化
从模板生成类和类的实例化
上一回在讲解QEMU中类继承机制的时候,讲到了Java反射机制。本回结合Java反射机制,具体看一下QEMU中从模板生成类和类实例化的相关代码。
再来回顾一下Java反射(Reflection)机制的流程。
(1)在Java中,对于一个类,首先在编写代码的时候要写一个class xxx的定义,编译好就放在.class文件中,这是处于纸面的状态。
这一步对应的就是QEMU中各个类的type_init函数,以及其调用的type_register_static函数。
以virtio block device这一层为例(hw/block/virtio-blk.c中):
static const TypeInfo virtio_blk_info = {
.name = TYPE_VIRTIO_BLK,
.parent = TYPE_VIRTIO_DEVICE,
.instance_size = sizeof(VirtIOBlock),
.instance_init = virtio_blk_instance_init,
.class_init = virtio_blk_class_init,
};
static void virtio_register_types(void)
{
type_register_static(&virtio_blk_info);
}
type_init(virtio_register_types)
定义一个QEMU模块会调用type_init,其是一个宏,在include/qemu/module.h中定义,如下:
#define type_init(function) module_init(function, MODULE_INIT_QOM)
由type_init宏的定义可以看出,type_init()中的参数是一个函数。此处,调用type_init(virtio_register_types)就相当于调用module_init(virtio_register_types, MODULE_INIT_QOM)。
MODULE_INIT_QOM是一个枚举值,其定义就在上边,如下:
typedef enum {
MODULE_INIT_MIGRATION,
MODULE_INIT_BLOCK,
MODULE_INIT_OPTS,
MODULE_INIT_QOM,
MODULE_INIT_TRACE,
MODULE_INIT_XEN_BACKEND,
MODULE_INIT_LIBQOS,
MODULE_INIT_FUZZ_TARGET,
MODULE_INIT_MAX
} module_init_type;
module_init也是一个宏,其定义也在include/qemu/module.h中,如下:
#ifdef BUILD_DSO
……
#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
register_module_init函数在util/module.c中,代码如下:
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);
}
属于MODULE_INIT_QOM这种类型的,有一个Module列表ModuleTypeList,列表中是一项一项的ModuleEntry,并且会初始化每一项的init函数为参数fn即function,在这里为virtio_register_types。
当然,MODULE_INIT_QOM这种类型会有很多的module,所有调用type_init()的地方都注册了一个MODULE_INIT_QOM类型的Module。
每一种Module既然要模拟某种(类)设备,那么就应该定义一种类型TypeImpl来表示这种设备。这其实是一种面向对象编程思想,只不过在QEMU中用的是纯C语言的实现。所以需要变相实现类和对象。
仍以上边的代码为例:
static const TypeInfo virtio_blk_info = {
.name = TYPE_VIRTIO_BLK,
.parent = TYPE_VIRTIO_DEVICE,
.instance_size = sizeof(VirtIOBlock),
.instance_init = virtio_blk_instance_init,
.class_init = virtio_blk_class_init,
};
static void virtio_register_types(void)
{
type_register_static(&virtio_blk_info);
}
type_init(virtio_register_types)
virtio_register_types函数会调用type_register_static函数,注册virtio_blk_info,可以认为这样就动态定义了一个类。这个类的名字是TYPE_VIRTIO_BLK(即"virtio-blk-device");其父类为TYPE_VIRTIO_DEVICE(即"virtio-device");类初始化函数为virtio_blk_class_init;如果用这个类声明一个对象,对象的大小应该为instance_size即virtio_blk_instance_init。
这样,类比Java反射的第一步所做的工作就完成了。
更多内容请看下回。