接前一篇文章: QEMU源码全解析24 —— QOM介绍(13)
本文内容参考:
《 QEMU /KVM》源码解析与应用 —— 李强,机械工业出版社
特此致谢!
本文开始对于属性ObjectProperty进行深入讲解。
ObjectProperty结构在include/qom/object.h中定义,代码如下:
- typedef struct ObjectProperty ObjectProperty;
-
- ……
-
- struct ObjectProperty
- {
- char *name;
- char *type;
- char *description;
- ObjectPropertyAccessor *get;
- ObjectPropertyAccessor *set;
- ObjectPropertyResolve *resolve;
- ObjectPropertyRelease *release;
- ObjectPropertyInit *init;
- void *opaque;
- QObject *defval;
- };
其中:
- name:表示名字;
- type:表示属性的类型。如有的属性是字符串,有的是bool类型,有的是link等其它更复杂的类型;
- description:表示对于属性的描述;
- get:对属性进行获取;
- set:对属性进行设置;
- resolve:对属性进行操作;
- release:对属性进行释放;
- opaque:指向一个具体的属性,如BoolProperty等。
每一种具体的属性都会有一个结构体来描述它。例如:表示布尔类型的属性的BoolProperty、表示字符串类型的属性的StringProperty以及表示link类型的属性的LinkProperty。三者都在qom/object.c中定义(不挨着),定义分别如下:
- typedef struct {
- union {
- Object **targetp;
- Object *target; /* if OBJ_PROP_LINK_DIRECT, when holding the pointer */
- ptrdiff_t offset; /* if OBJ_PROP_LINK_CLASS */
- };
- void (*check)(const Object *, const char *, Object *, Error **);
- ObjectPropertyLinkFlags flags;
- } LinkProperty;
-
- ……
-
- typedef struct StringProperty
- {
- char *(*get)(Object *, Error **);
- void (*set)(Object *, const char *, Error **);
- } StringProperty;
-
- ……
-
- typedef struct BoolProperty
- {
- bool (*get)(Object *, Error **);
- void (*set)(Object *, bool, Error **);
- } BoolProperty;
总结一下Object、ObjectProperty和各个具体属性的关系:
- Object(struct object)-> GHashTable *properties中存放着属性名到ObjectProperty(struct ObjectProperty)的映射。
- ObjectProperty -> void *opaque指向一个具体的属性。
下边介绍几个属性的操作接口。属性的添加分为类属性的添加和对象属性的添加。
对于对象属性来说,其属性添加是通过object_property_add接口完成的。object_property_add函数在qom/object.c中,代码如下:
- ObjectProperty *
- object_property_add(Object *obj, const char *name, const char *type,
- ObjectPropertyAccessor *get,
- ObjectPropertyAccessor *set,
- ObjectPropertyRelease *release,
- void *opaque)
- {
- return object_property_try_add(obj, name, type, get, set, release,
- opaque, &error_abort);
- }
该函数实际上是object_property_try_add函数的简单封装,object_property_try_add函数就在上边,代码如下:
- ObjectProperty *
- object_property_try_add(Object *obj, const char *name, const char *type,
- ObjectPropertyAccessor *get,
- ObjectPropertyAccessor *set,
- ObjectPropertyRelease *release,
- void *opaque, Error **errp)
- {
- ObjectProperty *prop;
- size_t name_len = strlen(name);
-
- if (name_len >= 3 && !memcmp(name + name_len - 3, "[*]", 4)) {
- int i;
- ObjectProperty *ret = NULL;
- char *name_no_array = g_strdup(name);
-
- name_no_array[name_len - 3] = '\0';
- for (i = 0; i < INT16_MAX; ++i) {
- char *full_name = g_strdup_printf("%s[%d]", name_no_array, i);
-
- ret = object_property_try_add(obj, full_name, type, get, set,
- release, opaque, NULL);
- g_free(full_name);
- if (ret) {
- break;
- }
- }
- g_free(name_no_array);
- assert(ret);
- return ret;
- }
-
- if (object_property_find(obj, name) != NULL) {
- error_setg(errp, "attempt to add duplicate property '%s' to object (type '%s')",
- name, object_get_typename(obj));
- return NULL;
- }
-
- prop = g_malloc0(sizeof(*prop));
-
- prop->name = g_strdup(name);
- prop->type = g_strdup(type);
-
- prop->get = get;
- prop->set = set;
- prop->release = release;
- prop->opaque = opaque;
-
- g_hash_table_insert(obj->properties, prop->name, prop);
- return prop;
- }
先不管通配符的情况,即if (name_len >= 3 && !memcmp(name + name_len - 3, "[*]", 4)) 条件判断中的内容,直接跳过往下看。首先调用object_property_find函数来确认所插入的属性是否已经存在。如果已存在,则报错返回,确保不会添加重复的属性。
随后分配一个ObjectProperty结构并使用函数参数进行初始化。代码片段如下:
- prop = g_malloc0(sizeof(*prop));
-
- prop->name = g_strdup(name);
- prop->type = g_strdup(type);
-
- prop->get = get;
- prop->set = set;
- prop->release = release;
- prop->opaque = opaque;
最后,调用以下代码将其插入到对象的properties域中,并返回此prop:
g_hash_table_insert(obj->properties, prop->name, prop);
翻回头来,看一下object_property_find函数的具体实现。object_property_find函数在同文件(qom/object.c)中,代码如下:
- ObjectProperty *object_property_find(Object *obj, const char *name)
- {
- ObjectProperty *prop;
- ObjectClass *klass = object_get_class(obj);
-
- prop = object_class_property_find(klass, name);
- if (prop) {
- return prop;
- }
-
- return g_hash_table_lookup(obj->properties, name);
- }
-
-
此函数首先调用object_get_class函数由Object结构对象(的指针)obj得到ObjectClass对象(的指针)kclass。object_get_class函数在qom/object.c中,代码如下:
- ObjectClass *object_get_class(Object *obj)
- {
- return obj->class;
- }
然后,调用object_class_property_find函数以确认自己所属的类以及所有父类都不存在这个属性。object_class_property_find函数同样在qom/object.c中,代码如下:
- ObjectProperty *object_class_property_find(ObjectClass *klass, const char *name)
- {
- ObjectClass *parent_klass;
-
- parent_klass = object_class_get_parent(klass);
- if (parent_klass) {
- ObjectProperty *prop =
- object_class_property_find(parent_klass, name);
- if (prop) {
- return prop;
- }
- }
-
- return g_hash_table_lookup(klass->properties, name);
- }
最后,在遍历(递归)完所有父类之后,调用g_hash_table_lookup(obj->properties, name);在自己的域中查找。
欲知后事如何,且看下回分解。