aboutsummaryrefslogtreecommitdiff
path: root/qom/object.c
diff options
context:
space:
mode:
Diffstat (limited to 'qom/object.c')
-rw-r--r--qom/object.c278
1 files changed, 216 insertions, 62 deletions
diff --git a/qom/object.c b/qom/object.c
index 4261944849..5e5b261103 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -13,8 +13,14 @@
#include "qemu/object.h"
#include "qemu-common.h"
#include "qapi/qapi-visit-core.h"
-#include "hw/qdev.h"
-// FIXME remove above
+
+/* TODO: replace QObject with a simpler visitor to avoid a dependency
+ * of the QOM core on QObject? */
+#include "qemu/qom-qobject.h"
+#include "qobject.h"
+#include "qbool.h"
+#include "qint.h"
+#include "qstring.h"
#define MAX_INTERFACES 32
@@ -63,6 +69,8 @@ typedef struct Interface
#define INTERFACE(obj) OBJECT_CHECK(Interface, obj, TYPE_INTERFACE)
+static Type type_interface;
+
static GHashTable *type_table_get(void)
{
static GHashTable *type_table;
@@ -368,11 +376,9 @@ void object_delete(Object *obj)
g_free(obj);
}
-static bool object_is_type(Object *obj, const char *typename)
+static bool type_is_ancestor(TypeImpl *type, TypeImpl *target_type)
{
- TypeImpl *target_type = type_get_by_name(typename);
- TypeImpl *type = obj->class->type;
- GSList *i;
+ assert(target_type);
/* Check if typename is a direct ancestor of type */
while (type) {
@@ -383,24 +389,45 @@ static bool object_is_type(Object *obj, const char *typename)
type = type_get_parent(type);
}
- /* Check if obj has an interface of typename */
- for (i = obj->interfaces; i; i = i->next) {
- Interface *iface = i->data;
-
- if (object_is_type(OBJECT(iface), typename)) {
- return true;
- }
- }
-
return false;
}
+static bool object_is_type(Object *obj, TypeImpl *target_type)
+{
+ return !target_type || type_is_ancestor(obj->class->type, target_type);
+}
+
Object *object_dynamic_cast(Object *obj, const char *typename)
{
+ TypeImpl *target_type = type_get_by_name(typename);
GSList *i;
- /* Check if typename is a direct ancestor */
- if (object_is_type(obj, typename)) {
+ /* Check if typename is a direct ancestor. Special-case TYPE_OBJECT,
+ * we want to go back from interfaces to the parent.
+ */
+ if (target_type && object_is_type(obj, target_type)) {
+ return obj;
+ }
+
+ /* Check if obj is an interface and its containing object is a direct
+ * ancestor of typename. In principle we could do this test at the very
+ * beginning of object_dynamic_cast, avoiding a second call to
+ * object_is_type. However, casting between interfaces is relatively
+ * rare, and object_is_type(obj, type_interface) would fail almost always.
+ *
+ * Perhaps we could add a magic value to the object header for increased
+ * (run-time) type safety and to speed up tests like this one. If we ever
+ * do that we can revisit the order here.
+ */
+ if (object_is_type(obj, type_interface)) {
+ assert(!obj->interfaces);
+ obj = INTERFACE(obj)->obj;
+ if (object_is_type(obj, target_type)) {
+ return obj;
+ }
+ }
+
+ if (!target_type) {
return obj;
}
@@ -408,21 +435,11 @@ Object *object_dynamic_cast(Object *obj, const char *typename)
for (i = obj->interfaces; i; i = i->next) {
Interface *iface = i->data;
- if (object_is_type(OBJECT(iface), typename)) {
+ if (object_is_type(OBJECT(iface), target_type)) {
return OBJECT(iface);
}
}
- /* Check if obj is an interface and its containing object is a direct
- * ancestor of typename */
- if (object_is_type(obj, TYPE_INTERFACE)) {
- Interface *iface = INTERFACE(obj);
-
- if (object_is_type(iface->obj, typename)) {
- return iface->obj;
- }
- }
-
return NULL;
}
@@ -435,7 +452,7 @@ static void register_interface(void)
.abstract = true,
};
- type_register_static(&interface_info);
+ type_interface = type_register_static(&interface_info);
}
device_init(register_interface);
@@ -648,6 +665,123 @@ void object_property_set(Object *obj, Visitor *v, const char *name,
}
}
+void object_property_set_str(Object *obj, const char *value,
+ const char *name, Error **errp)
+{
+ QString *qstr = qstring_from_str(value);
+ object_property_set_qobject(obj, QOBJECT(qstr), name, errp);
+
+ QDECREF(qstr);
+}
+
+char *object_property_get_str(Object *obj, const char *name,
+ Error **errp)
+{
+ QObject *ret = object_property_get_qobject(obj, name, errp);
+ QString *qstring;
+ char *retval;
+
+ if (!ret) {
+ return NULL;
+ }
+ qstring = qobject_to_qstring(ret);
+ if (!qstring) {
+ error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "string");
+ retval = NULL;
+ } else {
+ retval = g_strdup(qstring_get_str(qstring));
+ }
+
+ QDECREF(qstring);
+ return retval;
+}
+
+void object_property_set_link(Object *obj, Object *value,
+ const char *name, Error **errp)
+{
+ object_property_set_str(obj, object_get_canonical_path(value),
+ name, errp);
+}
+
+Object *object_property_get_link(Object *obj, const char *name,
+ Error **errp)
+{
+ char *str = object_property_get_str(obj, name, errp);
+ Object *target = NULL;
+
+ if (str && *str) {
+ target = object_resolve_path(str, NULL);
+ if (!target) {
+ error_set(errp, QERR_DEVICE_NOT_FOUND, str);
+ }
+ }
+
+ g_free(str);
+ return target;
+}
+
+void object_property_set_bool(Object *obj, bool value,
+ const char *name, Error **errp)
+{
+ QBool *qbool = qbool_from_int(value);
+ object_property_set_qobject(obj, QOBJECT(qbool), name, errp);
+
+ QDECREF(qbool);
+}
+
+bool object_property_get_bool(Object *obj, const char *name,
+ Error **errp)
+{
+ QObject *ret = object_property_get_qobject(obj, name, errp);
+ QBool *qbool;
+ bool retval;
+
+ if (!ret) {
+ return false;
+ }
+ qbool = qobject_to_qbool(ret);
+ if (!qbool) {
+ error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "boolean");
+ retval = false;
+ } else {
+ retval = qbool_get_int(qbool);
+ }
+
+ QDECREF(qbool);
+ return retval;
+}
+
+void object_property_set_int(Object *obj, int64_t value,
+ const char *name, Error **errp)
+{
+ QInt *qint = qint_from_int(value);
+ object_property_set_qobject(obj, QOBJECT(qint), name, errp);
+
+ QDECREF(qint);
+}
+
+int64_t object_property_get_int(Object *obj, const char *name,
+ Error **errp)
+{
+ QObject *ret = object_property_get_qobject(obj, name, errp);
+ QInt *qint;
+ int64_t retval;
+
+ if (!ret) {
+ return -1;
+ }
+ qint = qobject_to_qint(ret);
+ if (!qint) {
+ error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "int");
+ retval = -1;
+ } else {
+ retval = qint_get_int(qint);
+ }
+
+ QDECREF(qint);
+ return retval;
+}
+
const char *object_property_get_type(Object *obj, const char *name, Error **errp)
{
ObjectProperty *prop = object_property_find(obj, name);
@@ -695,6 +829,12 @@ void object_property_add_child(Object *obj, const char *name,
{
gchar *type;
+ /* Registering an interface object in the composition tree will mightily
+ * confuse object_get_canonical_path (which, on the other hand, knows how
+ * to get the canonical path of an interface object).
+ */
+ assert(!object_is_type(obj, type_interface));
+
type = g_strdup_printf("child<%s>", object_get_typename(OBJECT(child)));
object_property_add(obj, name, type, object_get_child_property,
@@ -730,6 +870,7 @@ static void object_set_link_property(Object *obj, Visitor *v, void *opaque,
bool ambiguous = false;
const char *type;
char *path;
+ gchar *target_type;
type = object_property_get_type(obj, name, NULL);
@@ -737,31 +878,30 @@ static void object_set_link_property(Object *obj, Visitor *v, void *opaque,
if (*child) {
object_unref(*child);
+ *child = NULL;
}
if (strcmp(path, "") != 0) {
Object *target;
- target = object_resolve_path(path, &ambiguous);
- if (target) {
- gchar *target_type;
-
- target_type = g_strdup(&type[5]);
- target_type[strlen(target_type) - 2] = 0;
+ /* Go from link<FOO> to FOO. */
+ target_type = g_strndup(&type[5], strlen(type) - 6);
+ target = object_resolve_path_type(path, target_type, &ambiguous);
- if (object_dynamic_cast(target, target_type)) {
- object_ref(target);
- *child = target;
+ if (ambiguous) {
+ error_set(errp, QERR_AMBIGUOUS_PATH, path);
+ } else if (target) {
+ object_ref(target);
+ *child = target;
+ } else {
+ target = object_resolve_path(path, &ambiguous);
+ if (target || ambiguous) {
+ error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, target_type);
} else {
- error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, type);
+ error_set(errp, QERR_DEVICE_NOT_FOUND, path);
}
-
- g_free(target_type);
- } else {
- error_set(errp, QERR_DEVICE_NOT_FOUND, path);
}
- } else {
- *child = NULL;
+ g_free(target_type);
}
g_free(path);
@@ -788,6 +928,10 @@ gchar *object_get_canonical_path(Object *obj)
Object *root = object_get_root();
char *newpath = NULL, *path = NULL;
+ if (object_is_type(obj, type_interface)) {
+ obj = INTERFACE(obj)->obj;
+ }
+
while (obj != root) {
ObjectProperty *prop = NULL;
@@ -823,17 +967,18 @@ gchar *object_get_canonical_path(Object *obj)
static Object *object_resolve_abs_path(Object *parent,
gchar **parts,
+ const char *typename,
int index)
{
ObjectProperty *prop;
Object *child;
if (parts[index] == NULL) {
- return parent;
+ return object_dynamic_cast(parent, typename);
}
if (strcmp(parts[index], "") == 0) {
- return object_resolve_abs_path(parent, parts, index + 1);
+ return object_resolve_abs_path(parent, parts, typename, index + 1);
}
prop = object_property_find(parent, parts[index]);
@@ -855,17 +1000,18 @@ static Object *object_resolve_abs_path(Object *parent,
return NULL;
}
- return object_resolve_abs_path(child, parts, index + 1);
+ return object_resolve_abs_path(child, parts, typename, index + 1);
}
static Object *object_resolve_partial_path(Object *parent,
gchar **parts,
+ const char *typename,
bool *ambiguous)
{
Object *obj;
ObjectProperty *prop;
- obj = object_resolve_abs_path(parent, parts, 0);
+ obj = object_resolve_abs_path(parent, parts, typename, 0);
QTAILQ_FOREACH(prop, &parent->properties, node) {
Object *found;
@@ -874,7 +1020,8 @@ static Object *object_resolve_partial_path(Object *parent,
continue;
}
- found = object_resolve_partial_path(prop->opaque, parts, ambiguous);
+ found = object_resolve_partial_path(prop->opaque, parts,
+ typename, ambiguous);
if (found) {
if (obj) {
if (ambiguous) {
@@ -893,7 +1040,8 @@ static Object *object_resolve_partial_path(Object *parent,
return obj;
}
-Object *object_resolve_path(const char *path, bool *ambiguous)
+Object *object_resolve_path_type(const char *path, const char *typename,
+ bool *ambiguous)
{
bool partial_path = true;
Object *obj;
@@ -913,9 +1061,10 @@ Object *object_resolve_path(const char *path, bool *ambiguous)
if (ambiguous) {
*ambiguous = false;
}
- obj = object_resolve_partial_path(object_get_root(), parts, ambiguous);
+ obj = object_resolve_partial_path(object_get_root(), parts,
+ typename, ambiguous);
} else {
- obj = object_resolve_abs_path(object_get_root(), parts, 1);
+ obj = object_resolve_abs_path(object_get_root(), parts, typename, 1);
}
g_strfreev(parts);
@@ -923,14 +1072,19 @@ Object *object_resolve_path(const char *path, bool *ambiguous)
return obj;
}
+Object *object_resolve_path(const char *path, bool *ambiguous)
+{
+ return object_resolve_path_type(path, TYPE_OBJECT, ambiguous);
+}
+
typedef struct StringProperty
{
char *(*get)(Object *, Error **);
void (*set)(Object *, const char *, Error **);
} StringProperty;
-static void object_property_get_str(Object *obj, Visitor *v, void *opaque,
- const char *name, Error **errp)
+static void property_get_str(Object *obj, Visitor *v, void *opaque,
+ const char *name, Error **errp)
{
StringProperty *prop = opaque;
char *value;
@@ -942,8 +1096,8 @@ static void object_property_get_str(Object *obj, Visitor *v, void *opaque,
}
}
-static void object_property_set_str(Object *obj, Visitor *v, void *opaque,
- const char *name, Error **errp)
+static void property_set_str(Object *obj, Visitor *v, void *opaque,
+ const char *name, Error **errp)
{
StringProperty *prop = opaque;
char *value;
@@ -959,8 +1113,8 @@ static void object_property_set_str(Object *obj, Visitor *v, void *opaque,
g_free(value);
}
-static void object_property_release_str(Object *obj, const char *name,
- void *opaque)
+static void property_release_str(Object *obj, const char *name,
+ void *opaque)
{
StringProperty *prop = opaque;
g_free(prop);
@@ -977,8 +1131,8 @@ void object_property_add_str(Object *obj, const char *name,
prop->set = set;
object_property_add(obj, name, "string",
- get ? object_property_get_str : NULL,
- set ? object_property_set_str : NULL,
- object_property_release_str,
+ get ? property_get_str : NULL,
+ set ? property_set_str : NULL,
+ property_release_str,
prop, errp);
}