接口
在一些设备类型定义中我们可以看到interfaces一栏。
static TypeInfo pc_dimm_info = {
.name = TYPE_PC_DIMM,
.parent = TYPE_DEVICE,
...
.interfaces = (InterfaceInfo[]) {
{ TYPE_MEMORY_DEVICE },
{ }
},
};
那这一栏是什么意思呢?让我们来进一步打开看看。
Interface也是一种类型
进一步看,可以发现在Qemu模型中接口也是一种类型,并且也有父子关系。
static TypeInfo interface_info = {
.name = TYPE_INTERFACE,
.class_size = sizeof(InterfaceClass),
.abstract = true,
};
static const TypeInfo memory_device_info = {
.name = TYPE_MEMORY_DEVICE,
.parent = TYPE_INTERFACE,
.class_size = sizeof(MemoryDeviceClass),
};
但是和普通类型不同,他们只有对应的Class,而没有object。
我们尝试把这两个类型画成图,或许能看得更清楚一些。
+---------------------------------------------------------------+
| |
v |
TypeInfo TypeImpl* InterfaceClass |
+---------------------+ +----------------------+ +-->+------------------------+ |
|name | type_new()---> |name | | |parent_class | |
| TYPE_INTERFACE | | TYPE_INTERFACE | | | (ObjectClass) | |
+---------------------+ |class ---|----+ | type ----|------+
| (ObjectClass*) | |concrete_class |
+----------------------+ | (ObjectClass*) |
|interface_type |
| (TypeImpl*) |
+------------------------+
|
|
|
v
+---------------------------------------------------------------+
| MemoryDeviceClass |
v +--------------------------+ |
TypeInfo TypeImpl* |InterfaceClass | |
+---------------------+ +----------------------+ +--> | +------------------------+ |
|name | type_new()---> |name | | | |parent_class | |
| TYPE_MEMORY_DEVICE| | TYPE_MEMORY_DEVICE | | | | (ObjectClass) | |
+---------------------+ |class ---|----+ | | type ----|---+
| (ObjectClass*) | | |concrete_class |
+----------------------+ | | (ObjectClass*) |
| |interface_type |
| | (TypeImpl*) |
| +------------------------+
|get_addr |
|set_addr |
|... |
| |
+--------------------------+
接口类型附属于设备类型
接口类型是一个很有意思的类型,刚才我们看到了TYPE_MEMORY_DEVICE会对应有一个MemoryDeviceClass。
对于普通的设备类型,那整个系统中就只会有这么一个对应的Class,但是接口类型则不是。
还是从代码上来看:
static void type_initialize(TypeImpl *ti)
{
...
for (i = 0; i < ti->num_interfaces; i++) {
TypeImpl *t = type_get_by_name(ti->interfaces[i].typename);
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);
}
...
}
对于定义了interfaces成员的类型,在初始化中将通过type_initialize_interface来创建自己的接口类型。 而这个类型不仅在系统中注册,还会添加到class->interfaces链表上。
+----------------------------------------------------------------+-----+
| | |
| MemoryDeviceClass | |
v +--------------------------+ | |
TypeImpl* |InterfaceClass | | |
+----------------------+ +--> | +------------------------+ | |
|name | | | |parent_class | | |
| TYPE_MEMORY_DEVICE | | | | (ObjectClass) | | |
|class ---|----+ | | type ----|----+ |
| (ObjectClass*) | | |interface_type | |
+----------------------+ | | (TypeImpl*) | |
^ | |concrete_class | |
| | | (ObjectClass*) | |
| | +------------------------+ |
| |get_addr | |
| |set_addr | |
| |... | |
| | | |
| +--------------------------+ |
| |
| |
| |
TypeImpl +----------------------------------------------------------------+ |
+--------------------------+ | | | |
|name | | | MemoryDeviceClass | |
| TYPE_PC_DIMM | v | +--------------------------+ | |
+--------------------------+ TypeImpl* | |InterfaceClass | | |
^ +----------------------+ +--> | +------------------------+ | |
| |name | | | |parent_class | | |
PCDIMMDeviceClass | TYPE_PC_DIMM:: | | | | (ObjectClass) | | |
+--------------------------+ | TYPE_MEMORY_DEVICE | | | | type ----|----+ |
|parent_class | +----->|class ---|----+ | |interface_type ----|-----------+
| (ObjectClass) | | | (ObjectClass*) | | | (TypeImpl*) |
| interfaces ----|------+ +----------------------+ | |concrete_class ----|----+
| | | | (ObjectClass*) | |
+--------------------------+ | +------------------------+ |
^ |get_addr | |
| |set_addr | |
| |... | |
| | | |
| +--------------------------+ |
| |
| |
+---------------------------------------------------------------------------------------------------------+
希望这个图能够对理解接口有一点点帮助。
设置接口类型的“虚函数”
接口类型重要的成员就是它的虚函数了,那谁在什么时候设置呢?
因为接口类型是从属于设备类型的,所以虚函数的设置在设备类型初始化函数中设置。
对于pc-dimm设备,这个函数就是pc_dimm_class_init中了。
DeviceClass *dc = DEVICE_CLASS(oc);
PCDIMMDeviceClass *ddc = PC_DIMM_CLASS(oc);
MemoryDeviceClass mdc = MEMORY_DEVICE_CLASS(oc);
mdc->get_addr = pc_dimm_md_get_addr;
mdc->set_addr = pc_dimm_md_set_addr;
从设备类型到接口类型
在上面这段代码中有一个有意思的地方就是怎么从设备类型PC_DIMM_CLASS转换到接口类型MEMORY_DEVICE_CLASS的
让我们来看一眼:
#define MEMORY_DEVICE_CLASS(klass) \
OBJECT_CLASS_CHECK(MemoryDeviceClass, (klass), TYPE_MEMORY_DEVICE)
#define OBJECT_CLASS_CHECK(class_type, class, name) \
((class_type *)object_class_dynamic_cast_assert(OBJECT_CLASS(class), (name), \
__FILE__, __LINE__, __func__))
经过这两个宏,最后会落到函数object_class_dynamic_cast()。
而这个函数就是沿着klass->interfaces链表查找名字为TYPE_MEMORY_DEVICE的类型。如果找到了唯一的,那就范围它。
怎么样,现在是不是能看清楚这个函数的意义,以及设备类到接口类的转换了?
Last updated