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

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

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

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

void module_call_init(module_init_type type)
{
    ModuleTypeList *l;
    ModuleEntry *e;

    if (modules_init_done[type]) {
        return;
    }

    l = find_type(type);

    QTAILQ_FOREACH(e, l, node) {
        e->init();
    }

    modules_init_done[type] = true;
}

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中,代码如下:

typedef enum {
    MODULE_INIT_MIGRATION,
    MODULE_INIT_BLOCK,
    MODULE_INIT_OPTS,
    MODULE_INIT_QOM,
    MODULE_INIT_TRACE,
    MODULE_INIT_XEN_BACKEND,
    MODULE_INIT_LIBQOS,
    MODULE_INIT_FUZZ_TARGET,
    MODULE_INIT_MAX
} module_init_type;

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

typedef QTAILQ_HEAD(, ModuleEntry) ModuleTypeList;

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

typedef struct QTailQLink {
    void *tql_next;
    struct QTailQLink *tql_prev;
} QTailQLink;

/*
 * Tail queue definitions.  The union acts as a poor man template, as if
 * it were QTailQLink<type>.
 */
#define QTAILQ_HEAD(name, type)                                         \
union name {                                                            \
        struct type *tqh_first;       /* first element */               \
        QTailQLink tqh_circ;          /* link for circular backwards list */ \
}

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

typedef union {
    struct ModuleEntry *tqh_first;
    QTailQLink tqh_circ;
} ModuleTypeList;

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

typedef struct ModuleEntry
{
    void (*init)(void);
    QTAILQ_ENTRY(ModuleEntry) node;
    module_init_type type;
} ModuleEntry;

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

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

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

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

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

static ModuleTypeList *find_type(module_init_type type)
{
    init_lists();

    return &init_type_list[type];
}

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

static void init_lists(void)
{
    static int inited;
    int i;

    if (inited) {
        return;
    }

    for (i = 0; i < MODULE_INIT_MAX; i++) {
        QTAILQ_INIT(&init_type_list[i]);
    }

    QTAILQ_INIT(&dso_init_list);

    inited = 1;
}

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

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

static ModuleTypeList init_type_list[MODULE_INIT_MAX];
static bool modules_init_done[MODULE_INIT_MAX];

static ModuleTypeList dso_init_list;

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

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

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

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

猜你喜欢

转载自blog.csdn.net/phmatthaus/article/details/131822467
今日推荐