接前一篇文章: QEMU源码全解析18 —— QOM介绍(7)
本文内容参考:
《 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中):
- 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);
-
- ……
-
- }
在类型的初始化函数type_initialize中会调用ti->class = g_malloc0(ti->class_size)语句来分配类型的class结构,此结构实际上代表了类型的信息,类似于C++、Java等面向对象语言中定义的一个类。从前文的分析看到,ti->class_size为TypeImpl中的值,如果类型本身没有定义,就会使用父类型的class_size进行初始化。
此处再贴出edu设备的定义以便于理解下边内容(hw/misc/edu.c):
- static void pci_edu_register_types(void)
- {
- static InterfaceInfo interfaces[] = {
- { INTERFACE_CONVENTIONAL_PCI_DEVICE },
- { },
- };
- static const TypeInfo edu_info = {
- .name = TYPE_PCI_EDU_DEVICE,
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(EduState),
- .instance_init = edu_instance_init,
- .class_init = edu_class_init,
- .interfaces = interfaces,
- };
-
- type_register_static(&edu_info);
- }
- 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中定义,代码如下:
- struct PCIDeviceClass {
- DeviceClass parent_class;
-
- void (*realize)(PCIDevice *dev, Error **errp);
- PCIUnregisterFunc *exit;
- PCIConfigReadFunc *config_read;
- PCIConfigWriteFunc *config_write;
-
- uint16_t vendor_id;
- uint16_t device_id;
- uint8_t revision;
- uint16_t class_id;
- uint16_t subsystem_vendor_id; /* only for header type = 0 */
- uint16_t subsystem_id; /* only for header type = 0 */
-
- /*
- * pci-to-pci bridge or normal device.
- * This doesn't mean pci host switch.
- * When card bus bridge is supported, this would be enhanced.
- */
- bool is_bridge;
-
- /* rom bar */
- const char *romfile;
- };
PCIDeviceClass表明了类属PCI设备的信息,如:表示设备制造商信息的vendor_id、表示设备信息的device_id以及读取PCI设备配置空间的config_read和config_write函数。
值得注意的是,PCIDeviceClass结构的第一个成员的类型DeviceClass结构,该结构描述的是属于“设备类型”的类型所具有的一些属性。在hw/core/qdev.c的device_type_info中可以看到:
- static const TypeInfo device_type_info = {
- .name = TYPE_DEVICE,
- .parent = TYPE_OBJECT,
- .instance_size = sizeof(DeviceState),
- .instance_init = device_initfn,
- .instance_post_init = device_post_init,
- .instance_finalize = device_finalize,
- .class_base_init = device_class_base_init,
- .class_init = device_class_init,
- .abstract = true,
- .class_size = sizeof(DeviceClass),
- .interfaces = (InterfaceInfo[]) {
- { TYPE_VMSTATE_IF },
- { TYPE_RESETTABLE_INTERFACE },
- { }
- }
- };
其中DeviceClass的定义在include/hw/qdev-core.h中,代码如下:
- struct DeviceClass {
- /*< private >*/
- ObjectClass parent_class;
- /*< public >*/
-
- DECLARE_BITMAP(categories, DEVICE_CATEGORY_MAX);
- const char *fw_name;
- const char *desc;
-
- /*
- * The underscore at the end ensures a compile-time error if someone
- * assigns to dc->props instead of using device_class_set_props.
- */
- Property *props_;
-
- /*
- * Can this device be instantiated with -device / device_add?
- * All devices should support instantiation with device_add, and
- * this flag should not exist. But we're not there, yet. Some
- * devices fail to instantiate with cryptic error messages.
- * Others instantiate, but don't work. Exposing users to such
- * behavior would be cruel; clearing this flag will protect them.
- * It should never be cleared without a comment explaining why it
- * is cleared.
- * TODO remove once we're there
- */
- bool user_creatable;
- bool hotpluggable;
-
- /* callbacks */
- /*
- * Reset method here is deprecated and replaced by methods in the
- * resettable class interface to implement a multi-phase reset.
- * TODO: remove once every reset callback is unused
- */
- DeviceReset reset;
- DeviceRealize realize;
- DeviceUnrealize unrealize;
-
- /* device state */
- const VMStateDescription *vmsd;
-
- /* Private to qdev / bus. */
- const char *bus_type;
- };
DeviceClass定义了设备类型相关的基本信息以及基本的回调函数。仍然注意其中第一个域,表示的是DeviceClass父类型的Class —— ObjectClass。前文已提到,ObjectClass是所有类型的基础,会被嵌入到对应的子Class的第一个域中。
ObjectClass、DeviceClass和PCIDeviceClass三者的包含与被包含关系如下图所示:
事实上,编译器为C++继承结构编译出来的内存分布与此是类似的。
下一回将讲解父类型成员域的初始化以及其它相关代码。