QEMU源码全解析16 —— QOM介绍(5)

88 篇文章 19 订阅

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

本文内容参考:

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

QEMU /KVM》源码解析与应用 —— 李强,机械工业出版社

特此致谢!

上一回讲完了QOM第一部分 —— 类型的注册。本回开始讲解第二部分 —— 类型的初始化。

2. 类型的初始化

在C++、Java等 面向对象编程 语言中,当程序中声明一个类型的时候,就已经知道了其类型的信息,如它的对象的大小。但是如果使用C语言来实现面向对象的这些特性,就需要特殊的处理了,要对类进行单独的初始化。在前文中,所有的类型信息TypeImpl已经保存在了一个哈希链表中,接下来,就需要对类进行初始化了。

类的初始化是通过type_initialize函数完成的,其在qom/object.c中,代码如下:

  1. static void type_initialize(TypeImpl *ti)
  2. {
  3. TypeImpl *parent;
  4. if (ti->class) {
  5. return;
  6. }
  7. ti->class_size = type_class_get_size(ti);
  8. ti->instance_size = type_object_get_size(ti);
  9. /* Any type with zero instance_size is implicitly abstract.
  10. * This means interface types are all abstract.
  11. */
  12. if (ti->instance_size == 0) {
  13. ti->abstract = true;
  14. }
  15. if (type_is_ancestor(ti, type_interface)) {
  16. assert(ti->instance_size == 0);
  17. assert(ti->abstract);
  18. assert(!ti->instance_init);
  19. assert(!ti->instance_post_init);
  20. assert(!ti->instance_finalize);
  21. assert(!ti->num_interfaces);
  22. }
  23. ti->class = g_malloc0(ti->class_size);
  24. parent = type_get_parent(ti);
  25. if (parent) {
  26. type_initialize(parent);
  27. GSList *e;
  28. int i;
  29. g_assert(parent->class_size <= ti->class_size);
  30. g_assert(parent->instance_size <= ti->instance_size);
  31. memcpy(ti->class, parent->class, parent->class_size);
  32. ti->class->interfaces = NULL;
  33. for (e = parent->class->interfaces; e; e = e->next) {
  34. InterfaceClass *iface = e->data;
  35. ObjectClass *klass = OBJECT_CLASS(iface);
  36. type_initialize_interface(ti, iface->interface_type, klass->type);
  37. }
  38. for (i = 0; i < ti->num_interfaces; i++) {
  39. TypeImpl *t = type_get_by_name(ti->interfaces[i].typename);
  40. if (!t) {
  41. error_report("missing interface '%s' for object '%s'",
  42. ti->interfaces[i].typename, parent->name);
  43. abort();
  44. }
  45. for (e = ti->class->interfaces; e; e = e->next) {
  46. TypeImpl *target_type = OBJECT_CLASS(e->data)->type;
  47. if (type_is_ancestor(target_type, t)) {
  48. break;
  49. }
  50. }
  51. if (e) {
  52. continue;
  53. }
  54. type_initialize_interface(ti, t, t);
  55. }
  56. }
  57. ti->class->properties = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
  58. object_property_free);
  59. ti->class->type = ti;
  60. while (parent) {
  61. if (parent->class_base_init) {
  62. parent->class_base_init(ti->class, ti->class_data);
  63. }
  64. parent = type_get_parent(parent);
  65. }
  66. if (ti->class_init) {
  67. ti->class_init(ti->class, ti->class_data);
  68. }
  69. }

type_initialize函数比较长,分段进行解析。

函数的参数(入参)是表示类型信息的TypeImpl类型的对象ti的地址或指针。type_initialize函数首先判断ti->class是否存在,如果不为空,则说明这个类型已经初始化过了,直接返回。

后边主要做了三件事:

(1)设置相关的field,如class_size和instance_size,并使用ti->class_size分配一个ObjectClass。代码片段如下:

  1. ti->class_size = type_class_get_size(ti);
  2. ti->instance_size = type_object_get_size(ti);
  3. /* Any type with zero instance_size is implicitly abstract.
  4. * This means interface types are all abstract.
  5. */
  6. if (ti->instance_size == 0) {
  7. ti->abstract = true;
  8. }
  9. if (type_is_ancestor(ti, type_interface)) {
  10. assert(ti->instance_size == 0);
  11. assert(ti->abstract);
  12. assert(!ti->instance_init);
  13. assert(!ti->instance_post_init);
  14. assert(!ti->instance_finalize);
  15. assert(!ti->num_interfaces);
  16. }
  17. ti->class = g_malloc0(ti->class_size);

为便于理解,再贴一下TypeImpl结构的定义(在qom/object.c中):

  1. truct TypeImpl
  2. {
  3. const char *name;
  4. size_t class_size;
  5. size_t instance_size;
  6. size_t instance_align;
  7. void (*class_init)(ObjectClass *klass, void *data);
  8. void (*class_base_init)(ObjectClass *klass, void *data);
  9. void *class_data;
  10. void (*instance_init)(Object *obj);
  11. void (*instance_post_init)(Object *obj);
  12. void (*instance_finalize)(Object *obj);
  13. bool abstract;
  14. const char *parent;
  15. TypeImpl *parent_type;
  16. ObjectClass *class;
  17. int num_interfaces;
  18. InterfaceImpl interfaces[MAX_INTERFACES];
  19. };

(2)(递归)初始化所有父类型,不仅包括实际的类型,还包括接口这种抽象类型。代码片段如下:

  1. parent = type_get_parent(ti);
  2. if (parent) {
  3. type_initialize(parent);
  4. GSList *e;
  5. int i;
  6. g_assert(parent->class_size <= ti->class_size);
  7. g_assert(parent->instance_size <= ti->instance_size);
  8. memcpy(ti->class, parent->class, parent->class_size);
  9. ti->class->interfaces = NULL;
  10. for (e = parent->class->interfaces; e; e = e->next) {
  11. InterfaceClass *iface = e->data;
  12. ObjectClass *klass = OBJECT_CLASS(iface);
  13. type_initialize_interface(ti, iface->interface_type, klass->type);
  14. }
  15. for (i = 0; i < ti->num_interfaces; i++) {
  16. TypeImpl *t = type_get_by_name(ti->interfaces[i].typename);
  17. if (!t) {
  18. error_report("missing interface '%s' for object '%s'",
  19. ti->interfaces[i].typename, parent->name);
  20. abort();
  21. }
  22. for (e = ti->class->interfaces; e; e = e->next) {
  23. TypeImpl *target_type = OBJECT_CLASS(e->data)->type;
  24. if (type_is_ancestor(target_type, t)) {
  25. break;
  26. }
  27. }
  28. if (e) {
  29. continue;
  30. }
  31. type_initialize_interface(ti, t, t);
  32. }
  33. }
  34. ti->class->properties = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
  35. object_property_free);
  36. ti->class->type = ti;

(3)依次调用所有父类的class_base_init以及自己的class_init函数。这也和C++类似,在初始化一个对象的时候会依次调用所有父类的构造函数。

  1. while (parent) {
  2. if (parent->class_base_init) {
  3. parent->class_base_init(ti->class, ti->class_data);
  4. }
  5. parent = type_get_parent(parent);
  6. }
  7. if (ti->class_init) {
  8. ti->class_init(ti->class, ti->class_data);
  9. }

实际上,type_initialize函数可以在很多地方调用,不过,只有在第一次调用的时候会进行初始化,之后的调用会由于ti->class不为空,在函数开始处就直接返回了。

欲知后事如何,且看下回分解。

举报

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