接前一篇文章: QEMU源码全解析 —— 块设备虚拟化(6)
本文内容参考:
《趣谈 Linux操作系统 》 —— 刘超,极客时间
《 QEMU /KVM源码解析与应用》 —— 李强,机械工业出版社
特此致谢!
QEMU初始化阶段的块设备虚拟化
从模板生成类和类的实例化
上一回在讲解QEMU中类继承机制的时候,讲到了Java反射机制。本回结合Java反射机制,具体看一下QEMU中从模板生成类和类实例化的相关代码。
再来回顾一下Java反射(Reflection)机制的流程。
(2)在Java中,当对于一个类已经写了一个class xxx的定义,并编译好放在了.class文件中(即处于纸面的状态)之后,Java会有一个Class对象,用于读取和表示这个纸面上的class xxx,从而生成真正的对象。
这一步对应的就是QEMU中,各个层次的类的class_init会生成XXXClass(这就相当于Java里边的对象)。
仍以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)
virtio_blk_info中的class_init指向的函数为virtio_blk_class_init。该函数在hw/block/virtio-blk.c中,代码如下:
static void virtio_blk_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
device_class_set_props(dc, virtio_blk_properties);
dc->vmsd = &vmstate_virtio_blk;
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
vdc->realize = virtio_blk_device_realize;
vdc->unrealize = virtio_blk_device_unrealize;
vdc->get_config = virtio_blk_update_config;
vdc->set_config = virtio_blk_set_config;
vdc->get_features = virtio_blk_get_features;
vdc->set_status = virtio_blk_set_status;
vdc->reset = virtio_blk_reset;
vdc->save = virtio_blk_save_device;
vdc->load = virtio_blk_load_device;
vdc->start_ioeventfd = virtio_blk_data_plane_start;
vdc->stop_ioeventfd = virtio_blk_data_plane_stop;
}
这里详细来看一下DeviceClass和VirtioDeviceClass的定义。实际上笔者在“QEMU源码全解析——virtio”系列文章中,已经详细解析过这一块。这里为了便于理解透彻,再次做一遍详细的解析。
DEVICE_CLASS是一个宏定义,但是在QEMU源码中搜索怎么都搜不到。后来几经周折,终于弄清楚了其具体细节。
要弄清楚DEVICE_CLASS,得先从hw/qdev-core.h中的OBJECT_DECLARE_TYPE讲起。
#define TYPE_DEVICE "device"
OBJECT_DECLARE_TYPE(DeviceState, DeviceClass, DEVICE)
OBJECT_DECLARE_TYPE的相关代码在include/qom/object.h中,代码如下:
/**
* OBJECT_DECLARE_TYPE:
* @InstanceType: instance struct name
* @ClassType: class struct name
* @MODULE_OBJ_NAME: the object name in uppercase with underscore separators
*
* This macro is typically used in a header file, and will:
*
* - create the typedefs for the object and class structs
* - register the type for use with g_autoptr
* - provide three standard type cast functions
*
* The object struct and class struct need to be declared manually.
*/
#define OBJECT_DECLARE_TYPE(InstanceType, ClassType, MODULE_OBJ_NAME) \
typedef struct InstanceType InstanceType; \
typedef struct ClassType ClassType; \
\
G_DEFINE_AUTOPTR_CLEANUP_FUNC(InstanceType, object_unref) \
\
DECLARE_OBJ_CHECKERS(InstanceType, ClassType, \
MODULE_OBJ_NAME, TYPE_##MODULE_OBJ_NAME)
那么带入实际值:
OBJECT_DECLARE_TYPE(DeviceState, DeviceClass, DEVICE)
得到:
typedef struct DeviceState DeviceState;
typedef struct DeviceClass DeviceClass;
G_DEFINE_AUTOPTR_CLEANUP_FUNC(DeviceState, object_unref)
DECLARE_OBJ_CHECKERS(DeviceState, DeviceClass, DEVICE, TYPE_DEVICE)
先给出完全展开后的实际值:
DECLARE_OBJ_CHECKERS宏的定义在include/qom/object.h中,如下:
/**
* DECLARE_OBJ_CHECKERS:
* @InstanceType: instance struct name
* @ClassType: class struct name
* @OBJ_NAME: the object name in uppercase with underscore separators
* @TYPENAME: type name
*
* Direct usage of this macro should be avoided, and the complete
* OBJECT_DECLARE_TYPE macro is recommended instead.
*
* This macro will provide the three standard type cast functions for a
* QOM type.
*/
#define DECLARE_OBJ_CHECKERS(InstanceType, ClassType, OBJ_NAME, TYPENAME) \
DECLARE_INSTANCE_CHECKER(InstanceType, OBJ_NAME, TYPENAME) \
\
DECLARE_CLASS_CHECKERS(ClassType, OBJ_NAME, TYPENAME)
DECLARE_INSTANCE_CHECKER宏的定义也在同文件(include/qom/object.h)中,如下:
/**
* DECLARE_INSTANCE_CHECKER:
* @InstanceType: instance struct name
* @OBJ_NAME: the object name in uppercase with underscore separators
* @TYPENAME: type name
*
* Direct usage of this macro should be avoided, and the complete
* OBJECT_DECLARE_TYPE macro is recommended instead.
*
* This macro will provide the instance type cast functions for a
* QOM type.
*/
#define DECLARE_INSTANCE_CHECKER(InstanceType, OBJ_NAME, TYPENAME) \
static inline G_GNUC_UNUSED InstanceType * \
OBJ_NAME(const void *obj) \
{ return OBJECT_CHECK(InstanceType, obj, TYPENAME); }
DECLARE_CLASS_CHECKERS宏的定义当然也在include/qom/object.h中,如下:
/**
* DECLARE_CLASS_CHECKERS:
* @ClassType: class struct name
* @OBJ_NAME: the object name in uppercase with underscore separators
* @TYPENAME: type name
*
* Direct usage of this macro should be avoided, and the complete
* OBJECT_DECLARE_TYPE macro is recommended instead.
*
* This macro will provide the class type cast functions for a
* QOM type.
*/
#define DECLARE_CLASS_CHECKERS(ClassType, OBJ_NAME, TYPENAME) \
static inline G_GNUC_UNUSED ClassType * \
OBJ_NAME##_GET_CLASS(const void *obj) \
{ return OBJECT_GET_CLASS(ClassType, obj, TYPENAME); } \
\
static inline G_GNUC_UNUSED ClassType * \
OBJ_NAME##_CLASS(const void *klass) \
{ return OBJECT_CLASS_CHECK(ClassType, klass, TYPENAME); }
这样,
#define DECLARE_OBJ_CHECKERS(InstanceType, ClassType, OBJ_NAME, TYPENAME) \
DECLARE_INSTANCE_CHECKER(InstanceType, OBJ_NAME, TYPENAME) \
\
DECLARE_CLASS_CHECKERS(ClassType, OBJ_NAME, TYPENAME)
实际上就相当于:
static inline G_GNUC_UNUSED InstanceType *OBJ_NAME(const void *obj)
{
return OBJECT_CHECK(InstanceType, obj, TYPENAME);
}
static inline G_GNUC_UNUSED ClassType *OBJ_NAME##_GET_CLASS(const void *obj)
{
return OBJECT_GET_CLASS(ClassType, obj, TYPENAME);
}
static inline G_GNUC_UNUSED ClassType *OBJ_NAME##_CLASS(const void *klass)
{
return OBJECT_CLASS_CHECK(ClassType, klass, TYPENAME);
}
进一步地,代入调用DECLARE_OBJ_CHECKERS()时传入的实际值,
DECLARE_OBJ_CHECKERS(DeviceState, DeviceClass, DEVICE, TYPE_DEVICE)
#define DECLARE_OBJ_CHECKERS(InstanceType, ClassType, OBJ_NAME, TYPENAME) \
DECLARE_INSTANCE_CHECKER(InstanceType, OBJ_NAME, TYPENAME) \
\
DECLARE_CLASS_CHECKERS(ClassType, OBJ_NAME, TYPENAME)
就得到:
DECLARE_INSTANCE_CHECKER(DeviceState, DEVICE, TYPE_DEVICE)
DECLARE_CLASS_CHECKERS(DeviceClass, DEVICE, TYPE_DEVICE)
进一步得到:
static inline G_GNUC_UNUSED DeviceState *DEVICE(const void *obj)
{
return OBJECT_CHECK(DeviceState, obj, TYPE_DEVICE);
}
static inline G_GNUC_UNUSED DeviceClass *DEVICE_GET_CLASS(const void *obj)
{
return OBJECT_GET_CLASS(DeviceClass, obj, TYPE_DEVICE);
}
static inline G_GNUC_UNUSED DeviceClass *DEVICE_CLASS(const void *klass)
{
return OBJECT_CLASS_CHECK(DeviceClass, klass, TYPE_DEVICE);
}
最终得到:
static inline G_GNUC_UNUSED DeviceState *DEVICE(const void *obj)
{
return OBJECT_CHECK(DeviceState, obj, "device");
}
static inline G_GNUC_UNUSED DeviceClass *DEVICE_GET_CLASS(const void *obj)
{
return OBJECT_GET_CLASS(DeviceClass, obj, "device");
}
static inline G_GNUC_UNUSED DeviceClass *DEVICE_CLASS(const void *klass)
{
return OBJECT_CLASS_CHECK(DeviceClass, klass, "device");
}
弄清楚了DEVICE_CLASS的定义,回到主线代码中。
static void virtio_blk_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
……
}
中的
DeviceClass *dc = DEVICE_CLASS(klass);
就是:
static inline G_GNUC_UNUSED DeviceClass *DEVICE_CLASS(const void *klass)
{
return OBJECT_CLASS_CHECK(DeviceClass, klass, "device");
}
DeviceClass *dc = OBJECT_CLASS_CHECK(DeviceClass, klass, "device");
本回解析了DEVICE_CLASS宏的展开,下一回继续解析VIRTIO_DEVICE_CLASS宏定义的展开。