接前一篇文章: QEMU源码全解析26 —— QOM介绍(15)
本文内容参考:
《 QEMU /KVM》源码解析与应用 —— 李强,机械工业出版社
特此致谢!
前文讲解了对象属性的设置接口。本文讲解对象属性的获取接口。实际上机制是很相似的。
对象属性的设置是通过object_property_get函数来完成的。该函数同样在qom/object.c中,代码如下:
bool object_property_get(Object *obj, const char *name, Visitor *v,
Error **errp)
{
Error *err = NULL;
ObjectProperty *prop = object_property_find_err(obj, name, errp);
if (prop == NULL) {
return false;
}
if (!prop->get) {
error_setg(errp, QERR_PERMISSION_DENIED);
return false;
}
prop->get(obj, v, name, prop->opaque, &err);
error_propagate(errp, err);
return !err;
}
其实object_property_get函数只是简单地调用了ObjectProperty的get函数。
每一种属性类型都有自己的get函数,如布尔(bool)、字符串(str)、enum(枚举)等。它们都在qom/object.c中,逐个来看:
static void property_get_str(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
StringProperty *prop = opaque;
char *value;
Error *err = NULL;
value = prop->get(obj, &err);
if (err) {
error_propagate(errp, err);
return;
}
visit_type_str(v, name, &value, errp);
g_free(value);
}
static void property_get_enum(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
EnumProperty *prop = opaque;
int value;
Error *err = NULL;
value = prop->get(obj, &err);
if (err) {
error_propagate(errp, err);
return;
}
visit_type_enum(v, name, &value, prop->lookup, errp);
}
static void property_get_bool(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
BoolProperty *prop = opaque;
bool value;
Error *err = NULL;
value = prop->get(obj, &err);
if (err) {
error_propagate(errp, err);
return;
}
visit_type_bool(v, name, &value, errp);
}
仍以bool为例进行讲解。可以看到,property_get_bool函数调用了具体属性(BoolProperty)的get函数,这是在创建这个属性的时候指定的。上一回已经讲过,对象属性的添加是通过object_property_add接口完成的。而bool类型对象属性的添加object_property_add_bool函数则是调用了此接口。object_property_add_bool函数在qom/object.c中,代码如下:
ObjectProperty *
object_property_add_bool(Object *obj, const char *name,
bool (*get)(Object *, Error **),
void (*set)(Object *, bool, Error **))
{
BoolProperty *prop = g_malloc0(sizeof(*prop));
prop->get = get;
prop->set = set;
return object_property_add(obj, name, "bool",
get ? property_get_bool : NULL,
set ? property_set_bool : NULL,
property_release_data,
prop);
}
从这个函数中就可以看到,BoolProperty结构的set成员函数为调用object_property_add_bool函数时传入的参数,形参为:void (*get)(Object *, Error **)。在object_property_add_bool函数中使用了上边的property_get_bool函数,在property_get_bool函数中最终调用了形参bool (*get)(Object *, Error **)对应的实参,即真正对象属性的获取函数。
仍以machine为例,hw/core/machine.c的machine_initfn函数代码如下:
static void machine_initfn(Object *obj)
{
MachineState *ms = MACHINE(obj);
MachineClass *mc = MACHINE_GET_CLASS(obj);
container_get(obj, "/peripheral");
container_get(obj, "/peripheral-anon");
ms->dump_guest_core = true;
ms->mem_merge = true;
ms->enable_graphics = true;
ms->kernel_cmdline = g_strdup("");
ms->ram_size = mc->default_ram_size;
ms->maxram_size = mc->default_ram_size;
if (mc->nvdimm_supported) {
Object *obj = OBJECT(ms);
ms->nvdimms_state = g_new0(NVDIMMState, 1);
object_property_add_bool(obj, "nvdimm",
machine_get_nvdimm, machine_set_nvdimm);
object_property_set_description(obj, "nvdimm",
"Set on/off to enable/disable "
"NVDIMM instantiation");
object_property_add_str(obj, "nvdimm-persistence",
machine_get_nvdimm_persistence,
machine_set_nvdimm_persistence);
object_property_set_description(obj, "nvdimm-persistence",
"Set NVDIMM persistence"
"Valid values are cpu, mem-ctrl");
}
if (mc->cpu_index_to_instance_props && mc->get_default_cpu_node_id) {
ms->numa_state = g_new0(NumaState, 1);
object_property_add_bool(obj, "hmat",
machine_get_hmat, machine_set_hmat);
object_property_set_description(obj, "hmat",
"Set on/off to enable/disable "
"ACPI Heterogeneous Memory Attribute "
"Table (HMAT)");
}
/* default to mc->default_cpus */
ms->smp.cpus = mc->default_cpus;
ms->smp.max_cpus = mc->default_cpus;
ms->smp.sockets = 1;
ms->smp.dies = 1;
ms->smp.clusters = 1;
ms->smp.cores = 1;
ms->smp.threads = 1;
machine_copy_boot_config(ms, &(BootConfiguration){ 0 });
}
关注此函数中的以下代码:
object_property_add_bool(obj, "hmat",
machine_get_hmat, machine_set_hmat);
代码中的machine_get_machine函数就是传入object_property_add_bool函数的与形参bool (*get)(Object *, Error **)对应的实参,也即对于machine对象属性进行获取时实际调用的函数。
至此,
对象的属性的添加、设置和获取就讲解完了。下一回开始讲解类的属性的添加、设置和获取。