QEMU源码全解析21 —— QOM介绍(10)

88 篇文章 19 订阅
本文是QEMU源码全解析系列的第21篇,主要探讨QOM(Quantum Object Model)中对象的构造与初始化过程。从-TypeInfo注册到TypeImpl初始化,再到根据QEMU命令行参数创建实例化对象,详细解析了如何通过device_init_func、qdev_device_add等函数完成设备对象的创建。
摘要由CSDN通过智能技术生成

接前一篇文章: QEMU源码全解析20 —— QOM介绍(9)

本文内容参考:

《趣谈 Linux操作系统 》 —— 刘超, 极客时间

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函数中有这样一行代码:

  1. qemu_opts_foreach(qemu_find_opts("device"),
  2. device_init_func, NULL, &error_fatal);

这里忽略QEMU参数构建以及其它跟对象构造主题关系不大的细节,只关注对象的构造。对每一个-device的参数,均会调用device_init_func函数。device_init_func函数在同文件(softmmu/vl.c)中,代码如下:

  1. static int device_init_func(void *opaque, QemuOpts *opts, Error **errp)
  2. {
  3. DeviceState *dev;
  4. dev = qdev_device_add(opts, errp);
  5. if (!dev && *errp) {
  6. error_report_err(*errp);
  7. return -1;
  8. } else if (dev) {
  9. object_unref(OBJECT(dev));
  10. }
  11. return 0;
  12. }

可以看到,device_init_func函数随即调用qdev_device_add函数进行设备的添加。qdev_device_add函数在softmmu/qdev-monitor.c中,代码如下:

  1. /* Takes ownership of @opts on success */
  2. DeviceState *qdev_device_add(QemuOpts *opts, Error **errp)
  3. {
  4. QDict *qdict = qemu_opts_to_qdict(opts, NULL);
  5. DeviceState *ret;
  6. ret = qdev_device_add_from_qdict(qdict, false, errp);
  7. if (ret) {
  8. qemu_opts_del(opts);
  9. }
  10. qobject_unref(qdict);
  11. return ret;
  12. }

qdev_device_add_from_qdict函数在同文件中,完整函数代码较长,在此不贴出,在其中调用了qdev_new函数以创建设备,代码片段如下:

  1. DeviceState *qdev_device_add_from_qdict(const QDict *opts,
  2. bool from_json, Error **errp)
  3. {
  4. ……
  5. /* create device */
  6. dev = qdev_new(driver);
  7. ……
  8. }

qdev_new函数在hw/core/qdev.c中,代码如下:

  1. DeviceState *qdev_new(const char *name)
  2. {
  3. if (!object_class_by_name(name)) {
  4. module_load_qom_one(name);
  5. }
  6. return DEVICE(object_new(name));
  7. }

最终通过object_new函数来构造对象。object_new函数在qom/object.c中,代码如下:

  1. bject *object_new(const char *typename)
  2. {
  3. TypeImpl *ti = type_get_by_name(typename);
  4. return object_new_with_type(ti);
  5. }

object_new函数中仍然先通过前文讲解过的type_get_by_name函数得到要转换到的TypeImpl,然后调用object_new_with_type函数。object_new_with_type函数同样在qom/object.c中,代码如下:

  1. static Object *object_new_with_type(Type type)
  2. {
  3. Object *obj;
  4. size_t size, align;
  5. void (*obj_free)(void *);
  6. g_assert(type != NULL);
  7. type_initialize(type);
  8. size = type->instance_size;
  9. align = type->instance_align;
  10. /*
  11. * Do not use qemu_memalign unless required. Depending on the
  12. * implementation, extra alignment implies extra overhead.
  13. */
  14. if (likely(align <= __alignof__(qemu_max_align_t))) {
  15. obj = g_malloc(size);
  16. obj_free = g_free;
  17. } else {
  18. obj = qemu_memalign(align, size);
  19. obj_free = qemu_vfree;
  20. }
  21. object_initialize_with_type(obj, size, type);
  22. obj->free = obj_free;
  23. return obj;
  24. }

object_initialize_with_type函数同样在qom/object.c中,代码如下:

  1. static void object_initialize_with_type(Object *obj, size_t size, TypeImpl *type)
  2. {
  3. type_initialize(type);
  4. g_assert(type->instance_size >= sizeof(Object));
  5. g_assert(type->abstract == false);
  6. g_assert(size >= type->instance_size);
  7. memset(obj, 0, type->instance_size);
  8. obj->class = type->class;
  9. object_ref(obj);
  10. object_class_property_init_all(obj);
  11. obj->properties = g_hash_table_new_full(g_str_hash, g_str_equal,
  12. NULL, object_property_free);
  13. object_init_with_type(obj, type);
  14. object_post_init_with_type(obj, type);
  15. }

这样,经过层层调用,最终调用到了object_init_with_type函数。

欲知此函数详情,且看下回分解。

举报

选择你想要举报的内容(必选)
  • 内容涉黄
  • 政治相关
  • 内容抄袭
  • 涉嫌广告
  • 内容侵权
  • 侮辱谩骂
  • 样式问题
  • 其他