QEMU源码全解析27 —— QOM介绍(16)

本文深入讲解QEMU中QOM(对象查询机制)的对象属性获取接口,通过`object_property_get`函数及其工作原理,阐述不同属性类型的获取函数,以bool属性为例进行详细分析,并展示在hw/core/machine.c中如何定义对象属性的获取函数。
摘要由CSDN通过智能技术生成

接前一篇文章: QEMU源码全解析26 —— QOM介绍(15)

本文内容参考:

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

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对象属性进行获取时实际调用的函数。

至此,

对象的属性的添加、设置和获取就讲解完了。下一回开始讲解类的属性的添加、设置和获取。