这一节专门对类型的层次结构进行介绍,QOM通过这种层次结构实现了类似C++中的继承概念。
edu设备的类型信息edu_info结构中有一个parent成员,这就指定了edu_info的父类型名称,edu的父类型是TYPE_PCI_DEVICE,表明edu设备被设计成为一个PCI设备。edu设备的父类型为TYPE_PCI_DEVICE,而TYPE_PCI_DEVICE的父类型为TYPE_DEVICE,而TYPE_DEVICE的父类型为TYPE_OBJECT
static const TypeInfo pci_device_type_info = {
.name = TYPE_PCI_DEVICE,
.parent = TYPE_DEVICE,
.instance_size = sizeof(PCIDevice),
.abstract = true,
.class_size = sizeof(PCIDeviceClass),
.class_init = pci_device_class_init,
.class_base_init = pci_device_class_base_init,
};
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),
};
所以这个edu类型的层次关系为
TYPE_PCI_DEVICE->TYPE_DEVICE->TYPE_OBJECT.
在type_initialize中会调用ti->class=g_malloc0(ti->class_size)来分配class的结构,这个结构实际代表了类型的信息。ti->class_size为TypeImpl中的值,如果类型本身没有定义就会使用父类型的class_size进行初始化。edu设备类型本身没有定义,所以它的class_size为TYPE_PCI_DEVICE中定义的值,即sizeof(PCIDeviceClass)
typedef 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.
*/
int is_bridge;
/* rom bar */
const char *romfile;
} PCIDeviceClass;
PCIDeviceClass表明了PCI设备的一些信息,表示设备上信息的vendor_id和设备信息device_id以及读取PCI设备配置空间的config_read和config_write函数。一个域是第一个成员DeviceClass的结构体,这描述的是属于“设备类型”的类型所具有的一些属性。
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),
};
typedef struct DeviceClass {
/*< private >*/
ObjectClass parent_class;
/*< public >*/
DECLARE_BITMAP(categories, DEVICE_CATEGORY_MAX);
const char *fw_name;
const char *desc;
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 */
DeviceReset reset;
DeviceRealize realize;
DeviceUnrealize unrealize;
/* device state */
const struct VMStateDescription *vmsd;
/* Private to qdev / bus. */
qdev_initfn init; /* TODO remove, once users are converted to realize */
qdev_event exit; /* TODO remove, once users are converted to unrealize */
const char *bus_type;
} DeviceClass;
struct ObjectClass
{
/*< private >*/
Type type;
GSList *interfaces;
const char *object_cast_cache[OBJECT_CLASS_CAST_CACHE];
const char *class_cast_cache[OBJECT_CLASS_CAST_CACHE];
ObjectUnparent *unparent;
GHashTable *properties;
};
父类型的成员域在什么时候初始化?在type_initialize中会调用以下代码来对父类型所占用的这部分空间进行初始化。
memcpy(ti->class, parent->class, parent->class_size);
类的初始化
ti->class_init(ti->class, ti->class_data);
第一个参数为ti->class,对edu而言就是刚刚分配的PCIDeviceClass,但是这个class_init回调的参数指定的类型是ObjectClass,所以需要完成ObjectClass到PCIDeviceClass的转换。
static void edu_class_init(ObjectClass *class, void *data)
{
PCIDeviceClass *k = PCI_DEVICE_CLASS(class);
k->realize = pci_edu_realize;
k->exit = pci_edu_uninit;
k->vendor_id = PCI_VENDOR_ID_QEMU;
k->device_id = 0x11e8;
k->revision = 0x10;
k->class_id = PCI_CLASS_OTHERS;
}
转换过程中,会用到动态转换,
ObjectClass *object_class_dynamic_cast(ObjectClass *class,
const char *typename)
{
ObjectClass *ret = NULL;
TypeImpl *target_type;
TypeImpl *type;
if (!class) {
return NULL;
}
/* A simple fast path that can trigger a lot for leaf classes. */
type = class->type;
if (type->name == typename) {
return class;
}
target_type = type_get_by_name(typename);
if (!target_type) {
/* target class type unknown, so fail the cast */
return NULL;
}
if (type->class->interfaces &&
type_is_ancestor(target_type, type_interface)) {
int found = 0;
GSList *i;
for (i = class->interfaces; i; i = i->next) {
ObjectClass *target_class = i->data;
if (type_is_ancestor(target_class->type, target_type)) {
ret = target_class;
found++;
}
}
/* The match was ambiguous, don't allow a cast */
if (found > 1) {
ret = NULL;
}
} else if (type_is_ancestor(type, target_type)) {
ret = class;
}
return ret;
}
第一个参数为需要转换的ObjectClass,第二个typename表示要转换到哪一个类型。