QEMU源码全解析8 —— 初始化所有Module

88 篇文章 19 订阅
本文深入解析QEMU中的module_call_init函数,探讨如何管理并初始化各种Module。通过分析QEMU的源码,了解QEMU如何作为中间人协调虚拟机与物理资源,并介绍ModuleTypeList、ModuleEntry等数据结构,以及QTAILQ宏的使用。
摘要由CSDN通过智能技术生成

接前一篇文章: QEMU源码全解析7 —— QEMU主函数

本文内容参考:

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

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

特此致谢!

上一篇文章讲到了qemu_init函数中的module_call_init(MODULE_INIT_OPTS)。本篇文章对这个函数进行解析。

module_call_init函数在util/module.c中,代码如下:

  1. void module_call_init(module_init_type type)
  2. {
  3. ModuleTypeList *l;
  4. ModuleEntry *e;
  5. if (modules_init_done[type]) {
  6. return;
  7. }
  8. l = find_type(type);
  9. QTAILQ_FOREACH(e, l, node) {
  10. e->init();
  11. }
  12. modules_init_done[type] = true;
  13. }

QEMU 作为中间人其实还是蛮辛苦的,对上面的 虚拟机 需要模拟各种各样的外部设备;而当虚拟机实际要使用物理资源的时候,对下面的物理机上的资源要进行请求。其工作模式有点儿类似于操作系统对接驱动。驱动要按照(符合)一定的(要求的)格式,才能被操作系统所接受,成为操作系统的一个模块。同理,QEMU为了模拟各类设备,也需要管理各种各样的模块,这些模块也要符合一定的格式。

由于这里传给module_init_call函数的参数值是MODULE_INIT_OPTS,因此在module_call_init中,会找到MODULE_INIT_OPTS这种类型对应的ModuleTypeList,找出列表中所有的ModuleEntry,然后调用每个ModuleEntry的init函数。

MODULE_INIT_OPTS的定义在include/qemu/module.h中,代码如下:

  1. typedef enum {
  2. MODULE_INIT_MIGRATION,
  3. MODULE_INIT_BLOCK,
  4. MODULE_INIT_OPTS,
  5. MODULE_INIT_QOM,
  6. MODULE_INIT_TRACE,
  7. MODULE_INIT_XEN_BACKEND,
  8. MODULE_INIT_LIBQOS,
  9. MODULE_INIT_FUZZ_TARGET,
  10. MODULE_INIT_MAX
  11. } module_init_type;

ModuleTypeList的定义同样在util/module.c中:

typedef QTAILQ_HEAD(, ModuleEntry) ModuleTypeList;

QTAILQ_HEAD的定义在include/qemu/queue.h中,代码如下:

  1. typedef struct QTailQLink {
  2. void *tql_next;
  3. struct QTailQLink *tql_prev;
  4. } QTailQLink;
  5. /*
  6. * Tail queue definitions. The union acts as a poor man template, as if
  7. * it were QTailQLink<type>.
  8. */
  9. #define QTAILQ_HEAD(name, type) \
  10. union name { \
  11. struct type *tqh_first; /* first element */ \
  12. QTailQLink tqh_circ; /* link for circular backwards list */ \
  13. }

因此,QTAILQ_HEAD的定义实际展开为:

  1. typedef union {
  2. struct ModuleEntry *tqh_first;
  3. QTailQLink tqh_circ;
  4. } ModuleTypeList;

module_call_init函数中ModuleEntry的定义同样在util/module.c中,代码如下:

  1. typedef struct ModuleEntry
  2. {
  3. void (*init)(void);
  4. QTAILQ_ENTRY(ModuleEntry) node;
  5. module_init_type type;
  6. } ModuleEntry;

QTAILQ_ENTRY的定义和QTAILQ_HEAD的定义一样,都在include/qemu/queue.h中,代码如下:

  1. #define QTAILQ_ENTRY(type) \
  2. union { \
  3. struct type *tqe_next; /* next element */ \
  4. QTailQLink tqe_circ; /* link for circular backwards list */ \
  5. }

而ModuleEntry结构中module_init_type的定义上边已经给出了。

这样,整个数据结构就比较清晰了。结合数据结构来看函数中的具体功能代码。

find_type函数在util/module.c中,代码如下:

  1. static ModuleTypeList *find_type(module_init_type type)
  2. {
  3. init_lists();
  4. return &init_type_list[type];
  5. }

而init_lists函数就在上边,代码如下:

  1. static void init_lists(void)
  2. {
  3. static int inited;
  4. int i;
  5. if (inited) {
  6. return;
  7. }
  8. for (i = 0; i < MODULE_INIT_MAX; i++) {
  9. QTAILQ_INIT(&init_type_list[i]);
  10. }
  11. QTAILQ_INIT(&dso_init_list);
  12. inited = 1;
  13. }

MODULE_INIT_MAX在上边的module_init_type定义中,值为8。

init_type_list和dso_init_list都在init_lists函数的上边:

  1. static ModuleTypeList init_type_list[MODULE_INIT_MAX];
  2. static bool modules_init_done[MODULE_INIT_MAX];
  3. static ModuleTypeList dso_init_list;

而QTAILQ_INIT的定义和QTAILQ_HEAD的定义一样,都在include/qemu/queue.h中,代码如下:

  1. /*
  2. * Tail queue functions.
  3. */
  4. #define QTAILQ_INIT(head) do { \
  5. (head)->tqh_first = NULL; \
  6. (head)->tqh_circ.tql_prev = &(head)->tqh_circ; \
  7. } while (/*CONSTCOND*/0)

在module_call_init函数中,会找到参数type(类型,如:MODULE_INIT_OPTS、MODULE_INIT_QOM)所对应的ModuleTypeList,找出列表中所有的ModuleEntry,然后调用每个ModuleEntry的init函数。

这里需要注意:在module_call_init调用的这一步,所有Module的init函数都已经被调用过了。

举报

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