QEMU源码全解析40 —— Machine(10)

接前一篇文章:QEMU源码全解析39 —— Machine(9)

本文内容参考:

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

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

特此致谢!

前边几篇文章围绕MACHINE函数的定义进行了探索,最终得到了MACHINE函数的代码,在include/hw/boards.h中,如下:

static inline G_GNUC_UNUSED MachineState *MACHINE(const void *obj)
{
    return OBJECT_CHECK(MachineState, obj, TYPE_MACHINE);
}

并且得到了OBJECT_CHECK宏展开后的函数代码:

static inline G_GNUC_UNUSED MachineState *MACHINE(const void *obj)
{
    return ((MachineState*)object_dynamic_cast_assert(OBJECT(obj), ("machine"), __FILE__, __LINE__, __func__));
}

现在要回过头来,看看qemu_create_machine函数(softmmu/vl.c中)的实际调用。代码片段如下:

 current_machine = MACHINE(object_new_with_class(OBJECT_CLASS(machine_class)));

老版本QEMU代码中这一句是这样:

扫描二维码关注公众号,回复: 16245149 查看本文章
 current_machine = MACHINE(object_new(object_class_get_name(OBJECT_CLASS(machine_class))));

之前MACHINE函数是重点,现在其参数object_new_with_class以及object_new函数成为了关注焦点。其均在qom/object.c中,代码如下:

Object *object_new(const char *typename)
{
    TypeImpl *ti = type_get_by_name(typename);

    return object_new_with_type(ti);
}
Object *object_new_with_class(ObjectClass *klass)
{
    return object_new_with_type(klass->type);
}

可以看到,甭管是哪一个函数,最终都会调用到object_new_with_type函数。不过这里要先看看新老两个版本的差异细节,也就是怎样“殊途同归”的。

先说新版本。新版本调用的是object_new_with_class(OBJECT_CLASS(machine_class)),这个machine_class是qemu_create_machine函数第一步以下函数得到的:

MachineClass *machine_class = select_machine(qdict, &error_fatal);

这一步的细节可以参看本系列之前文章:QEMU源码全解析34 —— Machine(4)

OBJECT_CLASS是一个宏,在include/qom/object.h中定义,代码如下:

/**
 * OBJECT_CLASS:
 * @class: A derivative of #ObjectClass.
 *
 * Converts a class to an #ObjectClass.  Since all objects are #Objects,
 * this function will always succeed.
 */
#define OBJECT_CLASS(class) \
    ((ObjectClass *)(class))

而ObjectClass结构的定义在include/qemu/typedefs.h中,如下:

typedef struct ObjectClass ObjectClass;

struct ObjectClass的定义在include/qom/object.h中,代码如下:

/**
 * struct ObjectClass:
 *
 * The base for all classes.  The only thing that #ObjectClass contains is an
 * integer type handle.
 */
struct ObjectClass
{
    /* private: */
    Type type;
    GSList *interfaces;

    const char *object_cast_cache[OBJECT_CLASS_CAST_CACHE];
    const char *class_cast_cache[OBJECT_CLASS_CAST_CACHE];

    ObjectUnparent *unparent;

    GHashTable *properties;
};

最终用到的是ObjectClass中的Type type成员。

再来看老版本。老版本调用的是object_new(object_class_get_name(OBJECT_CLASS(machine_class)))。OBJECT_CLASS宏和machine_class上边都已经说过了,object_class_get_name函数在qom/object.c中,代码如下:

const char *object_class_get_name(ObjectClass *klass)
{
    return klass->type->name;
}

看一下ObjectClass结构中Type类型的定义,在include/qom/object.h中,代码如下:

struct TypeImpl;
typedef struct TypeImpl *Type;

从这里就可以看到,实际上Type和TypeImpl是同宗同源的,TypeImpl就是struct TYpeImpl,而Type是struct TypeImpl *。

object_new函数中还调用了type_get_by_name函数,其同样在qom/object.c中,代码如下:

static TypeImpl *type_get_by_name(const char *name)
{
    if (name == NULL) {
        return NULL;
    }

    return type_table_lookup(name);
}

type_table_lookup函数在同文件中,代码如下:

static TypeImpl *type_table_lookup(const char *name)
{
    return g_hash_table_lookup(type_table_get(), name);
}

以上过程可能比较容易乱,我们在从头捋一下。

  • 新版本

新版本调用的是object_new_with_class(OBJECT_CLASS(machine_class)) 。逐层展开如下:

object_new_with_class(OBJECT_CLASS(machine_class)) --->

object_new_with_class(((ObjectClass *)(machine_class))) ---> 

object_new_with_type(((ObjectClass *)(machine_class))->type) 

  • 老版本

老版本调用的是object_new(object_class_get_name(OBJECT_CLASS(machine_class)))。逐层展开如下:

object_new(object_class_get_name(OBJECT_CLASS(machine_class))) ---> 

object_new(object_class_get_name(((ObjectClass *)(machine_class)))) ---> 

object_new(((ObjectClass *)(machine_class))->type->name) ---> 

object_new_with_type(type_get_by_name(((ObjectClass *)(machine_class))->type->name)) 

从两者最后(一行)代码的对比就能看得出来,新版本比旧版本省了一道事。明明ObjectClass->type可以直接获得,老版本还非得先ObjectClass->type->name再通过type_get_by_name回溯回ObjectClass->type。我看这次更新是很应该的且是要点赞的。

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

猜你喜欢

转载自blog.csdn.net/phmatthaus/article/details/132315185