接前一篇文章: QEMU源码全解析20 —— QOM介绍(9)
本文内容参考:
《 QEMU /KVM》源码解析与应用 —— 李强,机械工业出版社
特此致谢!
上一回讲完了QOM中类型的层次结构。本回开始讲解第三部分 —— 对象的构造与初始化初始化。
3. 对象的 QEMU 源码全解析21 —— QOM介绍(10)构造与初始化
先来总结回顾一下前面两部分的内容。首先,每个类型指定一个TypeInfo注册到系统中。然后,在系统运行初始化的时候会把TypeInfo转变成TypeImple放到一个哈希表中,这就是类型的注册即第一部分内容;系统会对这个哈希表中的每一个类型进行初始化,主要是设置TypeImpl的一些域以及调用类型的class_init函数,这就是类型的初始化即第二部分内容。
现在系统中已经有了所有类型的信息,并且这些类型的初始化函数也已经调用了。接着会根据需要(如QEMU命令行指定的参数),创建对应的实例化对象,也就是各个类型的object。下边来分析指定-device edu命令的情况。在softmmu/vl.c的qemu_create_cli_devices函数中有这样一行代码:
- qemu_opts_foreach(qemu_find_opts("device"),
- device_init_func, NULL, &error_fatal);
这里忽略QEMU参数构建以及其它跟对象构造主题关系不大的细节,只关注对象的构造。对每一个-device的参数,均会调用device_init_func函数。device_init_func函数在同文件(softmmu/vl.c)中,代码如下:
- static int device_init_func(void *opaque, QemuOpts *opts, Error **errp)
- {
- DeviceState *dev;
-
- dev = qdev_device_add(opts, errp);
- if (!dev && *errp) {
- error_report_err(*errp);
- return -1;
- } else if (dev) {
- object_unref(OBJECT(dev));
- }
- return 0;
- }
可以看到,device_init_func函数随即调用qdev_device_add函数进行设备的添加。qdev_device_add函数在softmmu/qdev-monitor.c中,代码如下:
- /* Takes ownership of @opts on success */
- DeviceState *qdev_device_add(QemuOpts *opts, Error **errp)
- {
- QDict *qdict = qemu_opts_to_qdict(opts, NULL);
- DeviceState *ret;
-
- ret = qdev_device_add_from_qdict(qdict, false, errp);
- if (ret) {
- qemu_opts_del(opts);
- }
- qobject_unref(qdict);
- return ret;
- }
qdev_device_add_from_qdict函数在同文件中,完整函数代码较长,在此不贴出,在其中调用了qdev_new函数以创建设备,代码片段如下:
- DeviceState *qdev_device_add_from_qdict(const QDict *opts,
- bool from_json, Error **errp)
- {
- ……
- /* create device */
- dev = qdev_new(driver);
- ……
- }
qdev_new函数在hw/core/qdev.c中,代码如下:
- DeviceState *qdev_new(const char *name)
- {
- if (!object_class_by_name(name)) {
- module_load_qom_one(name);
- }
- return DEVICE(object_new(name));
- }
最终通过object_new函数来构造对象。object_new函数在qom/object.c中,代码如下:
- bject *object_new(const char *typename)
- {
- TypeImpl *ti = type_get_by_name(typename);
-
- return object_new_with_type(ti);
- }
object_new函数中仍然先通过前文讲解过的type_get_by_name函数得到要转换到的TypeImpl,然后调用object_new_with_type函数。object_new_with_type函数同样在qom/object.c中,代码如下:
- static Object *object_new_with_type(Type type)
- {
- Object *obj;
- size_t size, align;
- void (*obj_free)(void *);
-
- g_assert(type != NULL);
- type_initialize(type);
-
- size = type->instance_size;
- align = type->instance_align;
-
- /*
- * Do not use qemu_memalign unless required. Depending on the
- * implementation, extra alignment implies extra overhead.
- */
- if (likely(align <= __alignof__(qemu_max_align_t))) {
- obj = g_malloc(size);
- obj_free = g_free;
- } else {
- obj = qemu_memalign(align, size);
- obj_free = qemu_vfree;
- }
-
- object_initialize_with_type(obj, size, type);
- obj->free = obj_free;
-
- return obj;
- }
-
object_initialize_with_type函数同样在qom/object.c中,代码如下:
- static void object_initialize_with_type(Object *obj, size_t size, TypeImpl *type)
- {
- type_initialize(type);
-
- g_assert(type->instance_size >= sizeof(Object));
- g_assert(type->abstract == false);
- g_assert(size >= type->instance_size);
-
- memset(obj, 0, type->instance_size);
- obj->class = type->class;
- object_ref(obj);
- object_class_property_init_all(obj);
- obj->properties = g_hash_table_new_full(g_str_hash, g_str_equal,
- NULL, object_property_free);
- object_init_with_type(obj, type);
- object_post_init_with_type(obj, type);
- }
这样,经过层层调用,最终调用到了object_init_with_type函数。
欲知此函数详情,且看下回分解。