QEMU源码全解析 —— 块设备虚拟化(7)

接前一篇文章: 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宏定义的展开。