抱歉,您的浏览器无法访问本站

本页面需要浏览器支持(启用)JavaScript


了解详情 >

Preface

关于为何需要使用device_class_set_parent_realize()的讨论

1
2
3
4
5
6
7
void device_class_set_parent_realize(DeviceClass *dc,
DeviceRealize dev_realize,
DeviceRealize *parent_realize)
{
*parent_realize = dc->realize;
dc->realize = dev_realize;
}

从逆向device_class_set_parent_realize的过程中探测到了一些QOM的设计哲学。

QOM系统的”对象构造”子系统

device_class_set_parent_realize()是让用户方便的构造”realize调用链”的API。因为用户自己定义的设备有自己的realize方法,需要将realize方法加入到QOM系统中,使用device_class_set_parent_realize()就能方便的创建”继承关系的调用链”。

Q: QOM不是实现了OOP的继承会自己调用父类的”构造”方法吗?为何还要手动构造调用链?

A: QOM的继承仅仅能实现instance_init的调用链,而不能调用父类的realize。这个根据TypeInfo的定义可知。而且realize是基于property系统(哈希表)的而不是基于TypeInfo。而QOM系统中一个设备的构造是大致分为了object_initialize, instance_initrealize三个部分的。所以需要手动构建realize调用链。至于为何QOM会将设备实例化过程分解为三个部分后面章节进行讨论。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
struct TypeInfo
{
const char *name;
const char *parent;

size_t instance_size;
size_t instance_align;
void (*instance_init)(Object *obj);
void (*instance_post_init)(Object *obj);
void (*instance_finalize)(Object *obj);

bool abstract;
size_t class_size;

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

InterfaceInfo *interfaces;
};

对于任意设备的实例化方法xxx_realize基本都有如下的格式

1
2
3
4
5
void xxx_realize() {
...
// 自身realize完成后 结尾调用parent_realize
xxxClass->parent_realize();
}

因此就会形成向上调用的调用链,会依据这样的结构依次向上对父类进行实例化。 而对于device_class_set_parent_realize()

1
2
3
4
5
6
7
8
9
device_class_set_parent_realize(dc, ppc_cpu_realize, &pcc->parent_realize);

void device_class_set_parent_realize(DeviceClass *dc,
DeviceRealize dev_realize,
DeviceRealize *parent_realize)
{
*parent_realize = dc->realize;
dc->realize = dev_realize;
}

总是会将dc->realize设备”叶子设备”的realize。这样一来,dc->realize就是设备realize过程的统一接口。调用dc->realize后就会根据上述调用链调用父设备。

而为什么我觉得dc->realize总是叶子设备的realize方法并作为统一接口呢,一来是device_class_set_parent_realize的代码总是dc->realize=dev_realize,二来是注释说TYPE_DEVICE(即dc)是没有realize方法的,刚好可以留用作统一接口。

Since TYPE_DEVICE doesn’t implement @realize and @unrealize, types
derived directly from it need not call their parent’s @realize and
@unrealize.
For other types consult the documentation and implementation of the
respective parent types.

几种”构造函数”的区别

  • object_initialize
    • TODO 未知
  • instance_init
  • realize

根据qdev-core.h中注释的描述,我猜测,instance_init似乎只是设置了一些初始值,这点和我们在OOP语言中对象实例(instance)一创建就会调用构造函数不同。

Trivial field initializations should go into #TypeInfo.instance_init.
Operations depending on @props static properties should go into @realize.
After successful realization, setting static properties will fail.

在QOM中对象真正的构造函数应该是realize。即根据构造参数(depending on properties)执行构造函数: “Operations depending on @props static properties should go into @realize.”。不过看具体的realize代码不是很能感受到这一点。e.g. ppc_cpu_realize

QOM将对象实例化过程分成了instance_initrealize两个阶段,instance_init是在TypeInfo中描述的会在object_new时递归调用object_new_with_type, object_init_with_type等操作。而realize是基于property(哈希表)的,需要在必要时人工realize父设备(即有些设备虽然继承,但是是不需要realize的)。见如下注释的说明:

Any type may override the @realize and/or @unrealize callbacks but needs
to call the parent type’s implementation if keeping their functionality
is desired. Refer to QOM documentation for further discussion and examples.

1
2
3
4
5
6
static void object_init_with_type(Object *obj, TypeImpl *ti)
{
if (type_has_parent(ti)) {
object_init_with_type(obj, type_get_parent(ti));
}
}

评论