QEMU源码全解析19 —— QOM介绍(8)

88 篇文章 19 订阅
本文深入解析QEMU的QOM(Quantum Object Model)中的类型层次结构,通过类比和代码示例阐述了从ObjectClass到DeviceClass、PCIDeviceClass的继承关系,介绍了如何在C语言中实现面向对象的概念,并预告了接下来关于父类型成员初始化的内容。
摘要由CSDN通过智能技术生成

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

本文内容参考:

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

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

特此致谢!

上一回讲到了 QEMU 的QOM中类型的层次结构,本文接着讲,把类型的层次结构讲完。

上文讲过,edu即TYPE_PCI_EDU_DEVICE类型的父类型是TYPE_PCI_DEVICE。当然,除了TYPE_PCI_DEVICE外,QEMU中还有其它类型,如TYPE_ISA_DEVICE,同样是以TYPE_DEVICE为父类型,表示的是ISA设备。仍然以《封神榜》做类比,这就相当于元始天尊徒弟不是只有玉鼎真人,还有哪吒的师傅太乙真人以及书胆姜子牙等。同理,TYPE_PCI_DEVICE也可以派生出其它的(子)类型(类比就是玉鼎真人除了杨戬外,也可以收其他徒弟)。总体上,QEMU使用的(所有)类型一起构成了以TYPE_OBJECT为根的树。

下边再从数据结构角度看一下类型的层次结构。

为了便于理解,再次贴出type_initialize函数中的相应代码片段(qom/object.c中):

  1. static void type_initialize(TypeImpl *ti)
  2. {
  3. TypeImpl *parent;
  4. if (ti->class) {
  5. return;
  6. }
  7. ti->class_size = type_class_get_size(ti);
  8. ti->instance_size = type_object_get_size(ti);
  9. /* Any type with zero instance_size is implicitly abstract.
  10. * This means interface types are all abstract.
  11. */
  12. if (ti->instance_size == 0) {
  13. ti->abstract = true;
  14. }
  15. if (type_is_ancestor(ti, type_interface)) {
  16. assert(ti->instance_size == 0);
  17. assert(ti->abstract);
  18. assert(!ti->instance_init);
  19. assert(!ti->instance_post_init);
  20. assert(!ti->instance_finalize);
  21. assert(!ti->num_interfaces);
  22. }
  23. ti->class = g_malloc0(ti->class_size);
  24. ……
  25. }

在类型的初始化函数type_initialize中会调用ti->class = g_malloc0(ti->class_size)语句来分配类型的class结构,此结构实际上代表了类型的信息,类似于C++、Java等面向对象语言中定义的一个类。从前文的分析看到,ti->class_size为TypeImpl中的值,如果类型本身没有定义,就会使用父类型的class_size进行初始化。

此处再贴出edu设备的定义以便于理解下边内容(hw/misc/edu.c):

  1. static void pci_edu_register_types(void)
  2. {
  3. static InterfaceInfo interfaces[] = {
  4. { INTERFACE_CONVENTIONAL_PCI_DEVICE },
  5. { },
  6. };
  7. static const TypeInfo edu_info = {
  8. .name = TYPE_PCI_EDU_DEVICE,
  9. .parent = TYPE_PCI_DEVICE,
  10. .instance_size = sizeof(EduState),
  11. .instance_init = edu_instance_init,
  12. .class_init = edu_class_init,
  13. .interfaces = interfaces,
  14. };
  15. type_register_static(&edu_info);
  16. }
  17. type_init(pci_edu_register_types)

对于edu设备来说,其类型本身没有定义,因此它的class_size为其父类型TYPE_PCI_DEVICE中定义的值,即pci_device_type_info中的class_size的值:sizeof(PCIDeviceClass)。

PCIDeviceClass结构在include/hw/pci/pci.h中定义,代码如下:

  1. struct PCIDeviceClass {
  2. DeviceClass parent_class;
  3. void (*realize)(PCIDevice *dev, Error **errp);
  4. PCIUnregisterFunc *exit;
  5. PCIConfigReadFunc *config_read;
  6. PCIConfigWriteFunc *config_write;
  7. uint16_t vendor_id;
  8. uint16_t device_id;
  9. uint8_t revision;
  10. uint16_t class_id;
  11. uint16_t subsystem_vendor_id; /* only for header type = 0 */
  12. uint16_t subsystem_id; /* only for header type = 0 */
  13. /*
  14. * pci-to-pci bridge or normal device.
  15. * This doesn't mean pci host switch.
  16. * When card bus bridge is supported, this would be enhanced.
  17. */
  18. bool is_bridge;
  19. /* rom bar */
  20. const char *romfile;
  21. };

PCIDeviceClass表明了类属PCI设备的信息,如:表示设备制造商信息的vendor_id、表示设备信息的device_id以及读取PCI设备配置空间的config_read和config_write函数。

值得注意的是,PCIDeviceClass结构的第一个成员的类型DeviceClass结构,该结构描述的是属于“设备类型”的类型所具有的一些属性。在hw/core/qdev.c的device_type_info中可以看到:

  1. static const TypeInfo device_type_info = {
  2. .name = TYPE_DEVICE,
  3. .parent = TYPE_OBJECT,
  4. .instance_size = sizeof(DeviceState),
  5. .instance_init = device_initfn,
  6. .instance_post_init = device_post_init,
  7. .instance_finalize = device_finalize,
  8. .class_base_init = device_class_base_init,
  9. .class_init = device_class_init,
  10. .abstract = true,
  11. .class_size = sizeof(DeviceClass),
  12. .interfaces = (InterfaceInfo[]) {
  13. { TYPE_VMSTATE_IF },
  14. { TYPE_RESETTABLE_INTERFACE },
  15. { }
  16. }
  17. };

其中DeviceClass的定义在include/hw/qdev-core.h中,代码如下:

  1. struct DeviceClass {
  2. /*< private >*/
  3. ObjectClass parent_class;
  4. /*< public >*/
  5. DECLARE_BITMAP(categories, DEVICE_CATEGORY_MAX);
  6. const char *fw_name;
  7. const char *desc;
  8. /*
  9. * The underscore at the end ensures a compile-time error if someone
  10. * assigns to dc->props instead of using device_class_set_props.
  11. */
  12. Property *props_;
  13. /*
  14. * Can this device be instantiated with -device / device_add?
  15. * All devices should support instantiation with device_add, and
  16. * this flag should not exist. But we're not there, yet. Some
  17. * devices fail to instantiate with cryptic error messages.
  18. * Others instantiate, but don't work. Exposing users to such
  19. * behavior would be cruel; clearing this flag will protect them.
  20. * It should never be cleared without a comment explaining why it
  21. * is cleared.
  22. * TODO remove once we're there
  23. */
  24. bool user_creatable;
  25. bool hotpluggable;
  26. /* callbacks */
  27. /*
  28. * Reset method here is deprecated and replaced by methods in the
  29. * resettable class interface to implement a multi-phase reset.
  30. * TODO: remove once every reset callback is unused
  31. */
  32. DeviceReset reset;
  33. DeviceRealize realize;
  34. DeviceUnrealize unrealize;
  35. /* device state */
  36. const VMStateDescription *vmsd;
  37. /* Private to qdev / bus. */
  38. const char *bus_type;
  39. };

DeviceClass定义了设备类型相关的基本信息以及基本的回调函数。仍然注意其中第一个域,表示的是DeviceClass父类型的Class —— ObjectClass。前文已提到,ObjectClass是所有类型的基础,会被嵌入到对应的子Class的第一个域中。

ObjectClass、DeviceClass和PCIDeviceClass三者的包含与被包含关系如下图所示:

事实上,编译器为C++继承结构编译出来的内存分布与此是类似的。

下一回将讲解父类型成员域的初始化以及其它相关代码。

举报

选择你想要举报的内容(必选)
  • 内容涉黄
  • 政治相关
  • 内容抄袭
  • 涉嫌广告
  • 内容侵权
  • 侮辱谩骂
  • 样式问题
  • 其他