Qemu class和instance(存在其他更优秀的文档解释此命题,请自行搜索)

1. Qemu的type_init是在constructor属性中执行的,也就是在main之前,也就是所有type_init的设备都会在main之前执行其type_register_static;
2. type_register_static会malloc TypeImpl数据结构,存放class_init/instance_init等回调函数和class_size/instance_size;
    需要重点说下class_size:这是所注册设备Class数据结构的sizeof,比如
        struct BusClass/pc中的PCMachineClass/struct PCIDeviceClass(称之为设备State)
        而class_size和instance_size的意义都是为了Qemu框架为设备class alloc上述结构体的内存,
        这些设备Class数据结构将会在其class_init被调用时传入。
        这些设备class内存的alloc发生在设备被启用时,这是因为type_register_static调用时尚未确定传入参数,
        并不能确定是否需要此设备。
    另外一个instance_size:这是所注册设备State数据结构的sizeof,比如
        struct Object/struct BusState/struct PCMachineState/struct PCIDevice等(称之为设备State)
        而这些设备State数据结构将会在其instanct_init被调用时传入,如果一个设备的instance_size为0,
        则此设备是虚拟设备。
        设备State内存的alloc时机其实是与设备State相近的,下文会有详解。
3. 这里需要解说一下这个instance和class这两个相差不远的老伙计存在的意义,
    我认为设计上instance(设备State)主要为了存放:
        状态(如pci的irq_state)、属性(如pci的msix_cap/machine的各MemoryRegion);
    而class最明显的标志就是,如果此设备有realize函数,则必在class。
    class的alloc和class_init的调用都先于instance_init。
    另外,设备可能仅有class或仅有instance。

4. 实际上type_register_static可以注册的函数不只有class_init和instance_init,我提供一个列表:
    class_init()
    instance_init()
    instance_post_init()
    罗列顺序即函数被调用顺序。
    另外还有一个class_base_init()有些奇怪,它的调用发生在child device对parent device进行递归检查时,
        也就是说,class_base_init是为自己可能存在的child device准备的,
        同时要注意的是,如存在多级child,每一级child的触发,都会发生对所有parent->class_base_init的调用
        这是一个被child device多次重复调用的接口
    instance_finalize和class_finalize,本文不叙述
5. 关于class和instance的数据结构内存alloc、回调触发,都发生在object_new函数
    object_new()是否调用由所注册设备被启用(创建虚拟机时通过machine型号、device参数、其他参数确定)决定,
    调用时机是在设备初始化的阶段。
    object_new首先根据设备所属类型(设备注册时传入的name字符串)查找TypeImpl,
    并触发type_initialize(TypeImpl *);
        type_initialize会先alloc class_size大小的内存,设备Class的内存由此存在,但是此内存是由多重含义的:
            利用指向结构体的指针如同指向结构体中首元素这一C语言特性,
            Qemu在struct xxxClass中做了套娃似的骚操作,如:
                struct PCIDeviceClass {
                    struct DeviceClass {
                        struct ObjectClass {
                            struct TypeImpl {
                                const char *name;

                ...
                struct PCMachineClass {
                    struct MachineClass {
                        struct ObjectClass {
                            struct TypeImpl {
                                const char *name;

                ...
            这就存在了指向这段内存的指针其实是指向const char *name的,
                也就是指向struct TypeImpl
                    也就是指向struct ObjectClass
                ...
            这种便利性在Qemu被各中发扬扩散。
            示例中结构体套娃都存在struct ObjectClass,这就是实质上的Qemu统一设备框架中的ObjectClass部分
            这种套娃式继承是struct+name同步的,即type_register_static所给parent字符串必须与
                struct xxxClass中的首元素一致,即必须为parent的struct,例如:
                static const TypeInfo vfio_pci_dev_info = {
                    .name = Type_VFIO_PCI, /* "vfio-pci" */
                    .parent = TYPE_PCI_DEVICE, /* "pci-device" */
                    .instance_size = sizeof(VFIOPCIDevice),
                ...
                对应的struct VFIOPCIDevice {
                    struct PCIDevice;
                    ...
                可以看到parent TYPE_PCI_DEVICE与首元素struct PCIDevice是需要一致的。
        然后,type_initialize会递归的检查设备的parent(字符串)并先触发parent的type_initialize;
        然后从当前device当前parent开始,一直到的最初代parent,全部进行class_base_init(如4.中描述)
        最后调用当前device的class_init。
    在type_initialize之后instance_size的内存同样被alloc,这段内存提供给了struct object,此处需要指出:
        如同class中的struct ObjectClass,instance中存在struct object,是Qemu统一设备框架中的Object部分,
        struct Object中包含struct ObjectClass。
        同样给出instance套娃示例:
            struct PCIDevice {
                struct DeviceState {
                    struct Object {
                        struct ObjectClass {
                            struct TypeImpl {
                                const char *name;

            ...
            struct PCMachineClass {
                struct MachineState {
                    struct Object {
                        struct ObjectClass {
                            struct TypeImpl {
                                const char *name;

            ...
        struct Object中的ObjectClass其实就是上方示例struct DeviceClass/struct MachineClass中的ObjectClass
        额外的,TypeImpl中同样存由ObjectClass,在Qemu统一设备框架内TypeImpl实质上完成ObjectClass的传递。
    随后开始的是instance_init的调用,首先递归检查设备的parent,并先触发parent的class_init;
    然后当前Device的class_init得到调用。
    最后一步是instance_post_init的调用,首先当前Device的instance_post_init被调用,
        然后递归检查并设备parent的instance_post_init。
 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值