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

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

本文内容参考:

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

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

特此致谢!

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

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

本回继续解析QEMU类Java反射机制的整个流程。上一回讲完了流程的第1步:

与之对应的QEMU中的步骤是:

type_init函数用于注册类。每一层都有class_init,用于从TypeImpl生产xxxClass。

接下来是与上述Java反射流程相对应流程的第2步:

以virtio_blk_info为例,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;
}

前文已讲过,virtio_blk_class_init函数中会生成:

typedef struct DeviceState DeviceState;
typedef struct DeviceClass DeviceClass;
 
G_DEFINE_AUTOPTR_CLEANUP_FUNC(DeviceState, object_unref)


​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");
}

​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");
}

也就是生成了struct DeviceClass和struct VirtioDeviceClass。

接下来是与上述Java反射流程相对应流程的第3步:

仍以virtio_blk_info为例,virtio_blk_info中的instance_init指向的函数为virtio_blk_instance_init。该函数也在hw/block/virtio-blk.c中,代码如下:

static void virtio_blk_instance_init(Object *obj)
{
    VirtIOBlock *s = VIRTIO_BLK(obj);
 
    device_add_bootindex_property(obj, &s->conf.conf.bootindex,
                                  "bootindex", "/disk@0,0",
                                  DEVICE(obj));
}

至此,QEMU中类Java反射机制的全部流程就全部讲解完了。