QEMU源码全解析16 —— QOM介绍(5)

这篇具有很好参考价值的文章主要介绍了QEMU源码全解析16 —— QOM介绍(5)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

接前一篇文章:QEMU源码全解析15 —— QOM介绍(4)

本文内容参考:

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

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

特此致谢!

上一回讲完了QOM第一部分 —— 类型的注册。本回开始讲解第二部分 —— 类型的初始化。

2. 类型的初始化

在C++、Java等面向对象编程语言中,当程序中声明一个类型的时候,就已经知道了其类型的信息,如它的对象的大小。但是如果使用C语言来实现面向对象的这些特性,就需要特殊的处理了,要对类进行单独的初始化。在前文中,所有的类型信息TypeImpl已经保存在了一个哈希链表中,接下来,就需要对类进行初始化了。

类的初始化是通过type_initialize函数完成的,其在qom/object.c中,代码如下:

static void type_initialize(TypeImpl *ti)
{
    TypeImpl *parent;

    if (ti->class) {
        return;
    }

    ti->class_size = type_class_get_size(ti);
    ti->instance_size = type_object_get_size(ti);
    /* Any type with zero instance_size is implicitly abstract.
     * This means interface types are all abstract.
     */
    if (ti->instance_size == 0) {
        ti->abstract = true;
    }
    if (type_is_ancestor(ti, type_interface)) {
        assert(ti->instance_size == 0);
        assert(ti->abstract);
        assert(!ti->instance_init);
        assert(!ti->instance_post_init);
        assert(!ti->instance_finalize);
        assert(!ti->num_interfaces);
    }
    ti->class = g_malloc0(ti->class_size);

    parent = type_get_parent(ti);
    if (parent) {
        type_initialize(parent);
        GSList *e;
        int i;

        g_assert(parent->class_size <= ti->class_size);
        g_assert(parent->instance_size <= ti->instance_size);
        memcpy(ti->class, parent->class, parent->class_size);
        ti->class->interfaces = NULL;

        for (e = parent->class->interfaces; e; e = e->next) {
            InterfaceClass *iface = e->data;
            ObjectClass *klass = OBJECT_CLASS(iface);

            type_initialize_interface(ti, iface->interface_type, klass->type);
        }

        for (i = 0; i < ti->num_interfaces; i++) {
            TypeImpl *t = type_get_by_name(ti->interfaces[i].typename);
            if (!t) {
                error_report("missing interface '%s' for object '%s'",
                             ti->interfaces[i].typename, parent->name);
                abort();
            }
            for (e = ti->class->interfaces; e; e = e->next) {
                TypeImpl *target_type = OBJECT_CLASS(e->data)->type;

                if (type_is_ancestor(target_type, t)) {
                    break;
                }
            }

            if (e) {
                continue;
            }

            type_initialize_interface(ti, t, t);
        }
    }

    ti->class->properties = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
                                                  object_property_free);

    ti->class->type = ti;

    while (parent) {
        if (parent->class_base_init) {
            parent->class_base_init(ti->class, ti->class_data);
        }
        parent = type_get_parent(parent);
    }

    if (ti->class_init) {
        ti->class_init(ti->class, ti->class_data);
    }
}

type_initialize函数比较长,分段进行解析。

函数的参数(入参)是表示类型信息的TypeImpl类型的对象ti的地址或指针。type_initialize函数首先判断ti->class是否存在,如果不为空,则说明这个类型已经初始化过了,直接返回。

后边主要做了三件事:

(1)设置相关的field,如class_size和instance_size,并使用ti->class_size分配一个ObjectClass。代码片段如下:

    ti->class_size = type_class_get_size(ti);
    ti->instance_size = type_object_get_size(ti);
    /* Any type with zero instance_size is implicitly abstract.
     * This means interface types are all abstract.
     */
    if (ti->instance_size == 0) {
        ti->abstract = true;
    }
    if (type_is_ancestor(ti, type_interface)) {
        assert(ti->instance_size == 0);
        assert(ti->abstract);
        assert(!ti->instance_init);
        assert(!ti->instance_post_init);
        assert(!ti->instance_finalize);
        assert(!ti->num_interfaces);
    }
    ti->class = g_malloc0(ti->class_size);

为便于理解,再贴一下TypeImpl结构的定义(在qom/object.c中):

truct TypeImpl
{
    const char *name;

    size_t class_size;

    size_t instance_size;
    size_t instance_align;

    void (*class_init)(ObjectClass *klass, void *data);
    void (*class_base_init)(ObjectClass *klass, void *data);

    void *class_data;

    void (*instance_init)(Object *obj);
    void (*instance_post_init)(Object *obj);
    void (*instance_finalize)(Object *obj);

    bool abstract;

    const char *parent;
    TypeImpl *parent_type;

    ObjectClass *class;

    int num_interfaces;
    InterfaceImpl interfaces[MAX_INTERFACES];
};

(2)(递归)初始化所有父类型,不仅包括实际的类型,还包括接口这种抽象类型。代码片段如下:

    parent = type_get_parent(ti);
    if (parent) {
        type_initialize(parent);
        GSList *e;
        int i;

        g_assert(parent->class_size <= ti->class_size);
        g_assert(parent->instance_size <= ti->instance_size);
        memcpy(ti->class, parent->class, parent->class_size);
        ti->class->interfaces = NULL;

        for (e = parent->class->interfaces; e; e = e->next) {
            InterfaceClass *iface = e->data;
            ObjectClass *klass = OBJECT_CLASS(iface);

            type_initialize_interface(ti, iface->interface_type, klass->type);
        }

        for (i = 0; i < ti->num_interfaces; i++) {
            TypeImpl *t = type_get_by_name(ti->interfaces[i].typename);
            if (!t) {
                error_report("missing interface '%s' for object '%s'",
                             ti->interfaces[i].typename, parent->name);
                abort();
            }
            for (e = ti->class->interfaces; e; e = e->next) {
                TypeImpl *target_type = OBJECT_CLASS(e->data)->type;

                if (type_is_ancestor(target_type, t)) {
                    break;
                }
            }

            if (e) {
                continue;
            }

            type_initialize_interface(ti, t, t);
        }
    }

    ti->class->properties = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
                                                  object_property_free);

    ti->class->type = ti;

(3)依次调用所有父类的class_base_init以及自己的class_init函数。这也和C++类似,在初始化一个对象的时候会依次调用所有父类的构造函数。

    while (parent) {
        if (parent->class_base_init) {
            parent->class_base_init(ti->class, ti->class_data);
        }
        parent = type_get_parent(parent);
    }

    if (ti->class_init) {
        ti->class_init(ti->class, ti->class_data);
    }

实际上,type_initialize函数可以在很多地方调用,不过,只有在第一次调用的时候会进行初始化,之后的调用会由于ti->class不为空,在函数开始处就直接返回了。

欲知后事如何,且看下回分解。文章来源地址https://www.toymoban.com/news/detail-612407.html

到了这里,关于QEMU源码全解析16 —— QOM介绍(5)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • QEMU源码全解析 —— PCI设备模拟(6)

    接前一篇文章: 上一回讲到了pci_edu_realize函数中的pci_register_bar函数,本回对于其进行详细解析。 再次贴出pci_register_bar函数源码,在hw/pci/pci.c中,代码如下: (1)首先根据region_num找到PCIDevice-io_regions数组中对应的项。PCI设备的MMIO存放在PCIIORegion结构体中,结构体中保存了

    2024年01月16日
    浏览(39)
  • QEMU源码全解析 —— PCI设备模拟(7)

    接前一篇文章: 上一回讲解了pci_edu_realize函数中的pci_register_bar函数,本回开始对于edu设备的MMIO读写函数进行解析。 操作系统与PCI设备交互的主要方式是PIO和MMIO。MMIO虽然是一段内存,但是其没有EPT映射,在虚拟机访问设备的MMIO时,会产生VM Exit;KVM识别此MMIO访问并且将该访

    2024年01月22日
    浏览(35)
  • qemu-kvm IO优化

    主要是磁盘方面的IO资源优化  四个方面去着手优化: 1. 磁盘的类型有IDE 、SATA 以及virtio 三种   建议使用 virtio 2. 磁盘缓存模式   目前KVM这块支持5种磁盘缓存模式,writethrough、writeback、none、directsync或者unsafe。一般用到的就是前面3种,后面两种几乎不会使用。   writethrou

    2023年04月08日
    浏览(35)
  • kvm qemu虚拟机的创建和启动

    qemu-img create -f qcow2 win1021H1.qcow2 10G sudo qemu-system-x86_64 -enable-kvm -m 8G -smp 4 -boot once=d -cdrom ./iso/cn_windows_7_enterprise_with_sp1_x64_dvd_u_677685.iso -hda ./win7_x64.qcow2 -vnc :1 -usb -usbdevice tablet 如果没有指定-hda ./win7.qcow2,则在安装系统的时候没有磁盘,如下图片是增加了之后才有的磁盘 默认不

    2024年02月12日
    浏览(52)
  • QEMU-KVM网络特性协商与虚拟机通信

    深入了解QEMU-KVM在启动虚拟机时如何通过代理进行网络前后端特性协商,包括与DPDK vhost-user和guest virtio-net驱动的交互。

    2024年02月01日
    浏览(34)
  • 巨页内存与Qemu/KVM虚拟化内存优化

    在虚拟化环境中,需要对虚拟机的优化,其中包括在某些情况下利用巨页内存进行内存的优化以提高虚拟机性能。那么什么是巨页内存?巨页内存有什么好处?Qemu/KVM虚拟化环境下如何使用巨页内存?本文将对这几个问题进行阐述。 对于内存管理,大多数现代操作系统都采用

    2024年02月07日
    浏览(48)
  • python可视化管理kvm虚拟机(使用libvirt、qemu连接虚拟机)

    对于云计算的实践,在虚拟机上面布置kvm虚拟机后使用python调用libvirt库进行远程可视化管理,实现输出虚拟机信息、新建虚拟机、删除虚拟机等功能,并在虚拟机集群上面运行mpi代码。 用pycharm专业版连接kvm的步骤见本文章。 mpi代码见本文章。

    2024年02月16日
    浏览(41)
  • qemu+kvm安装银河麒麟V10SP1 arm64 虚拟机

    系统镜像 Kylin-Desktop-V10-SP1-Release-2107-arm64.iso QEMU_EFI.fd(下载地址 http://releases.linaro.org/components/kernel/uefi-linaro/16.02/release/qemu64/QEMU_EFI.fd) 注:麒麟系统要求磁盘大小在50G以上. 参数说明: -m 4096 指定内存大小,单位MB -cpu cortex-a72 CPU 型号 -smp 8,cores=8,threads=1,sockets=1 1颗CPU,8核8线

    2024年01月21日
    浏览(113)
  • FT2000+ qemu kvm openEuer crash 分析 频繁设置CPU online及cgroup导致进程卡死、不调度故障

    https://hknaruto.blog.csdn.net/article/details/130498823 内核版本信息  突然就坚挺起来,长时间稳定运行 待续 十几分钟后,终端已卡死 ,两个终端均无响应,但是gnome还活着,图形界面还能动 重启虚拟机 kvm内,安装好crash分析环境 下载安装debuginfo包 http://debuginfo.centos.org/8/aarch64/Pack

    2024年02月02日
    浏览(45)
  • ubuntu18.04下pass-through直通realteck PCI设备到qemu-kvm虚拟机实践

    设备直通是一种虚拟化资源分配方式,通过将物理设备直通给虚拟机环境,达到虚拟机可以直接访问物理设备的目的,直通功能对设备的要求不高,不需要设备支持PF/VF,目前市面上的显卡/网卡一般都支持直通。典型场景比如有两块显卡,一块主机用,另一块虚拟机用,主板

    2024年02月03日
    浏览(54)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包