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

接前一篇文章: QEMU源码全解析 —— 块设备虚拟化(7)

本文内容参考:

《趣谈 Linux操作系统 》 —— 刘超,极客时间

QEMU /KVM源码解析与应用》 —— 李强,机械工业出版社

特此致谢!

QEMU初始化阶段的块设备虚拟化

从模板生成类和类的实例化

上一回在讲解Java反射机制流程的时候,讲到了第2步,再来回顾一下:

上一回讲解virtio_blk_info中的class_init指向的函数virtio_blk_class_init,解析了DeviceClass和DEVICE_CLASS宏。

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;
}

本回解析第2行:

    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);

依样画葫芦。

VIRTIO_DEVICE_CLASS是一个宏定义,同样在QEMU源码中不能直接搜索到。要弄清楚VIRTUAL_DEVICE_CLASS,得先从include/hw/virtio/virtio.h中的OBJECT_DECLARE_TYPE讲起。

#define TYPE_VIRTIO_DEVICE "virtio-device"
OBJECT_DECLARE_TYPE(VirtIODevice, VirtioDeviceClass, VIRTIO_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(VirtIODevice, VirtioDeviceClass, VIRTIO_DEVICE)

得到:

    typedef struct VirtIODevice VirtIODevice;
    typedef struct VirtioDeviceClass VirtioDeviceClass;
 
    G_DEFINE_AUTOPTR_CLEANUP_FUNC(VirtIODevice, object_unref)
 
    DECLARE_OBJ_CHECKERS(VirtIODevice, VirtioDeviceClass, VIRTIO_DEVICE, TYPE_VIRTIO_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(VirtIODevice, VirtioDeviceClass, VIRTIO_DEVICE, TYPE_VIRTIO_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(VirtIODevice, VIRTIO_DEVICE, TYPE_VIRTIO_DEVICE)
 
DECLARE_CLASS_CHECKERS(VirtioDeviceClass, VIRTIO_DEVICE, TYPE_VIRTIO_DEVICE)

进一步得到:

static inline G_GNUC_UNUSED VirtIODevice *VIRTIO_DEVICE(const void *obj)
{
    return OBJECT_CHECK(VirtIODevice, obj, TYPE_DEVICE);
}
 
static inline G_GNUC_UNUSED VirtioDeviceClass *VIRTIO_DEVICE_GET_CLASS(const void *obj)
{
    return OBJECT_GET_CLASS(VirtioDeviceClass, obj, TYPE_DEVICE);
}
 
static inline G_GNUC_UNUSED VirtioDeviceClass *VIRTIO_DEVICE_CLASS(const void *klass)
{
    return OBJECT_CLASS_CHECK(VirtioDeviceClass, klass, TYPE_DEVICE);
}

最终得到:

​static inline G_GNUC_UNUSED VirtIODevice *VIRTIO_DEVICE(const void *obj)
{
    return OBJECT_CHECK(VirtIODevice, obj, "virtio-device");
}
 
static inline G_GNUC_UNUSED VirtioDeviceClass *VIRTIO_DEVICE_GET_CLASS(const void *obj)
{
    return OBJECT_GET_CLASS(VirtioDeviceClass, obj, "virtio-device");
}
 
static inline G_GNUC_UNUSED VirtioDeviceClass *VIRTIO_DEVICE_CLASS(const void *klass)
{
    return OBJECT_CLASS_CHECK(VirtioDeviceClass, klass, "virtio-device");
}

综合所有的内容,

    typedef struct VirtIODevice VirtIODevice;
    typedef struct VirtioDeviceClass VirtioDeviceClass;
 
    G_DEFINE_AUTOPTR_CLEANUP_FUNC(VirtIODevice, object_unref)
 
    DECLARE_OBJ_CHECKERS(VirtIODevice, VirtioDeviceClass, VIRTIO_DEVICE, TYPE_VIRTIO_DEVICE)

完整内容是:

​typedef struct VirtIODevice VirtIODevice;
typedef struct VirtioDeviceClass VirtioDeviceClass;
 
G_DEFINE_AUTOPTR_CLEANUP_FUNC(VirtIODevice, object_unref)
 
​static inline G_GNUC_UNUSED VirtIODevice *VIRTIO_DEVICE(const void *obj)
{
    return OBJECT_CHECK(VirtIODevice, obj, "virtio-device");
}
 
static inline G_GNUC_UNUSED VirtioDeviceClass *VIRTIO_DEVICE_GET_CLASS(const void *obj)
{
    return OBJECT_GET_CLASS(VirtioDeviceClass, obj, "virtio-device");
}
 
static inline G_GNUC_UNUSED VirtioDeviceClass *VIRTIO_DEVICE_CLASS(const void *klass)
{
    return OBJECT_CLASS_CHECK(VirtioDeviceClass, klass, "virtio-device");
}

再次与系统展开内容进行对比:

弄清楚了DEVICE_CLASS的定义,回到主线代码中。

static void virtio_blk_class_init(ObjectClass *klass, void *data)
{
    DeviceClass *dc = DEVICE_CLASS(klass);
    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
    ……
}

中的

    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);

就是:

static inline G_GNUC_UNUSED VirtioDeviceClass *VIRTIO_DEVICE_CLASS(const void *klass)
{
    return OBJECT_CLASS_CHECK(VirtioDeviceClass, klass, "virtio-device");
}
    VirtioDeviceClass *vdc = OBJECT_CLASS_CHECK(VirtioDeviceClass, klass, "virtio-device");

这样,反映射调用流程的第2步就解析完了,DeviceClass和VirtioDeviceClass已经生成了。

欲知后事如何,且看下回分解。