接前一篇文章:QEMU源码全解析39 —— Machine(9)
本文内容参考:
《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代码中这一句是这样:
![](/qrcode.jpg)
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。我看这次更新是很应该的且是要点赞的。
欲知后事如何,且看下回分解。