接上一篇文章中介绍的qom的基本用法和qom面向对象实现原理,这一篇讲一下qom实现的源码
1.初始化函数的注册
类型注册的调用接口是type_init(xxx_register_types)
,type_init
是个宏定义,最终原理是gcc 的constructor
属性,添加这个属性描述的函数为初始化函数,会在main函数执行之前执行,最后宏定义的作用就是在xxx_register_types
之前加上一个__attribute__((constructor))
,再改改名字。目的是在main函数之前就注册好类型。
2.类的注册
在xxx_register_types
逻辑里面通常是注册类调用的函数是type_register_static(&xxx_info);
,我们追踪一下这个函数的实现,源码主要在qom/object.c
中:
->type_register_static
->type_register
->type_register_internal
->type_new
->type_table_add
->g_hash_table_insert
g_hash_table_insert
暂时不深究,认为是一个hash_table容器即可。现在我们的类就注册好了。下面看一下类的初始化逻辑。
3.sysbus的初始化
sysbus的初始化的初始化源自vl.c
main函数里面的 qemu_register_reset(qbus_reset_all_fn, sysbus_get_default());
开始初始化最初的sysbus总线,这个是qemu默认有的总线,可以类比linux内核的platform总线。之后开始一系列sysbus的初始化,下面看一下过程
sysbus.c
->sysbus_get_default
->main_system_bus_create
->qbus_create_inplace
bus.c
->qbus_create_inplace
->object_initialize
objetc.c
->object_initialize
->object_initialize_with_type
->type_initialize
->ti->class_init(ti->class, ti->class_data);
->object_init_with_type
->ti->instance_init(obj);
3.设备的初始化
设备的初始化源自vl.c
main中的 qemu_opts_foreach(qemu_find_opts("device"),device_init_func, NULL, &error_fatal);
,根据命令行参数来做初始化,具体命令解析不细说,感兴趣的自行分析。下面看一下设备初始化流程
vl.c
->device_init_func
->qdev_device_add
qdev-monitor.c
->qdev_device_add
->qemu_opt_get
->qdev_get_device_class
->object_class_by_name
->dev = DEVICE(object_new(driver));
->object_new
->object_property_set_bool(OBJECT(dev), true, "realized", &err);
object_class_by_name
主要是获取一些信息,object_new
是真正的设备初始化,逻辑就是对object_initialize_with_type
的封装,上面已经介绍过object_initialize_with_type
了,下面还是看一下细节:
objetc.c
->object_new
->object_initialize_with_type
->type_initialize
->ti->class_init(ti->class, ti->class_data);
->object_init_with_type
->ti->instance_init(obj);
大多数设备有注册realize函数,这个函数是在什么时候触发点呢?秘密就在object_property_set_bool(OBJECT(dev), true, "realized", &err);
,这个函数有点绕,来看一下具体过程
首先是注册过程,设备的realized属性在对象初始化的时候注册,逻辑在父类qdev中,来看一下:
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),
};
关注device_initfn函数的逻辑
qdev.c
->device_initfn
->object_property_add_bool(obj, "realized", device_get_realized, device_set_realized, NULL);
->device_get_realized
->return dev->realized;
->device_set_realized
->dc->realize(dev, &local_err);
看到在设置设备对象的realized属性且参数为true的时候会调用设备的realize函数。这就对应上了上面的属性设置。到这里从命令行参数到设备初始化就讲完了