#include "qom/object_interfaces.h"
#include "qemu/cutils.h"
#include "qapi/visitor.h"
-#include "qapi-visit.h"
#include "qapi/string-input-visitor.h"
#include "qapi/string-output-visitor.h"
+#include "qapi/qapi-builtin-visit.h"
#include "qapi/qmp/qerror.h"
#include "trace.h"
/* TODO: replace QObject with a simpler visitor to avoid a dependency
* of the QOM core on QObject? */
#include "qom/qom-qobject.h"
-#include "qapi/qmp/qobject.h"
#include "qapi/qmp/qbool.h"
+#include "qapi/qmp/qnum.h"
#include "qapi/qmp/qstring.h"
#define MAX_INTERFACES 32
if (ti->instance_size == 0) {
ti->abstract = true;
}
-
+ if (type_is_ancestor(ti, type_interface)) {
+ assert(ti->instance_size == 0);
+ assert(ti->abstract);
+ assert(!ti->instance_init);
+ assert(!ti->instance_post_init);
+ assert(!ti->instance_finalize);
+ assert(!ti->num_interfaces);
+ }
ti->class = g_malloc0(ti->class_size);
parent = type_get_parent(ti);
GSList *e;
int i;
- g_assert_cmpint(parent->class_size, <=, ti->class_size);
+ g_assert(parent->class_size <= ti->class_size);
memcpy(ti->class, parent->class, parent->class_size);
ti->class->interfaces = NULL;
ti->class->properties = g_hash_table_new_full(
g_assert(type != NULL);
type_initialize(type);
- g_assert_cmpint(type->instance_size, >=, sizeof(Object));
+ g_assert(type->instance_size >= sizeof(Object));
g_assert(type->abstract == false);
- g_assert_cmpint(size, >=, type->instance_size);
+ g_assert(size >= type->instance_size);
memset(obj, 0, type->instance_size);
obj->class = type->class;
object_initialize_with_type(data, size, type);
}
+void object_initialize_child(Object *parentobj, const char *propname,
+ void *childobj, size_t size, const char *type,
+ Error **errp, ...)
+{
+ va_list vargs;
+
+ va_start(vargs, errp);
+ object_initialize_childv(parentobj, propname, childobj, size, type, errp,
+ vargs);
+ va_end(vargs);
+}
+
+void object_initialize_childv(Object *parentobj, const char *propname,
+ void *childobj, size_t size, const char *type,
+ Error **errp, va_list vargs)
+{
+ Error *local_err = NULL;
+ Object *obj;
+
+ object_initialize(childobj, size, type);
+ obj = OBJECT(childobj);
+
+ object_set_propv(obj, &local_err, vargs);
+ if (local_err) {
+ goto out;
+ }
+
+ object_property_add_child(parentobj, propname, obj, &local_err);
+ if (local_err) {
+ goto out;
+ }
+
+ if (object_dynamic_cast(obj, TYPE_USER_CREATABLE)) {
+ user_creatable_complete(obj, &local_err);
+ if (local_err) {
+ object_unparent(obj);
+ goto out;
+ }
+ }
+
+ /*
+ * Since object_property_add_child added a reference to the child object,
+ * we can drop the reference added by object_initialize(), so the child
+ * property will own the only reference to the object.
+ */
+ object_unref(obj);
+
+out:
+ if (local_err) {
+ error_propagate(errp, local_err);
+ object_unref(obj);
+ }
+}
+
static inline bool object_property_is_child(ObjectProperty *prop)
{
return strstart(prop->type, "child<", NULL);
object_property_del_all(obj);
object_deinit(obj, ti);
- g_assert_cmpint(obj->ref, ==, 0);
+ g_assert(obj->ref == 0);
if (obj->free) {
obj->free(obj);
}
return list;
}
+static gint object_class_cmp(gconstpointer a, gconstpointer b)
+{
+ return strcasecmp(object_class_get_name((ObjectClass *)a),
+ object_class_get_name((ObjectClass *)b));
+}
+
+GSList *object_class_get_list_sorted(const char *implements_type,
+ bool include_abstract)
+{
+ return g_slist_sort(object_class_get_list(implements_type, include_abstract),
+ object_class_cmp);
+}
+
void object_ref(Object *obj)
{
if (!obj) {
if (!obj) {
return;
}
- g_assert_cmpint(obj->ref, >, 0);
+ g_assert(obj->ref > 0);
/* parent always holds a reference to its children */
if (atomic_fetch_dec(&obj->ref) == 1) {
return val;
}
+void object_class_property_iter_init(ObjectPropertyIterator *iter,
+ ObjectClass *klass)
+{
+ g_hash_table_iter_init(&iter->iter, klass->properties);
+ iter->nextclass = object_class_get_parent(klass);
+}
+
ObjectProperty *object_class_property_find(ObjectClass *klass, const char *name,
Error **errp)
{
QString *qstr = qstring_from_str(value);
object_property_set_qobject(obj, QOBJECT(qstr), name, errp);
- QDECREF(qstr);
+ qobject_unref(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) {
+
+ retval = g_strdup(qobject_get_try_str(ret));
+ if (!retval) {
error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name, "string");
- retval = NULL;
- } else {
- retval = g_strdup(qstring_get_str(qstring));
}
- qobject_decref(ret);
+ qobject_unref(ret);
return retval;
}
QBool *qbool = qbool_from_bool(value);
object_property_set_qobject(obj, QOBJECT(qbool), name, errp);
- QDECREF(qbool);
+ qobject_unref(qbool);
}
bool object_property_get_bool(Object *obj, const char *name,
if (!ret) {
return false;
}
- qbool = qobject_to_qbool(ret);
+ qbool = qobject_to(QBool, ret);
if (!qbool) {
error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name, "boolean");
retval = false;
retval = qbool_get_bool(qbool);
}
- qobject_decref(ret);
+ qobject_unref(ret);
return retval;
}
QNum *qnum = qnum_from_int(value);
object_property_set_qobject(obj, QOBJECT(qnum), name, errp);
- QDECREF(qnum);
+ qobject_unref(qnum);
}
int64_t object_property_get_int(Object *obj, const char *name,
return -1;
}
- qnum = qobject_to_qnum(ret);
+ qnum = qobject_to(QNum, ret);
if (!qnum || !qnum_get_try_int(qnum, &retval)) {
error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name, "int");
retval = -1;
}
- qobject_decref(ret);
+ qobject_unref(ret);
return retval;
}
QNum *qnum = qnum_from_uint(value);
object_property_set_qobject(obj, QOBJECT(qnum), name, errp);
- QDECREF(qnum);
+ qobject_unref(qnum);
}
uint64_t object_property_get_uint(Object *obj, const char *name,
if (!ret) {
return 0;
}
- qnum = qobject_to_qnum(ret);
+ qnum = qobject_to(QNum, ret);
if (!qnum || !qnum_get_try_uint(qnum, &retval)) {
error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name, "uint");
retval = 0;
}
- qobject_decref(ret);
+ qobject_unref(ret);
return retval;
}
return;
}
- object_ref(new_target);
*child = new_target;
- object_unref(old_target);
+ if (prop->flags == OBJ_PROP_LINK_STRONG) {
+ object_ref(new_target);
+ object_unref(old_target);
+ }
}
static Object *object_resolve_link_property(Object *parent, void *opaque, const gchar *part)
{
LinkProperty *prop = opaque;
- if ((prop->flags & OBJ_PROP_LINK_UNREF_ON_RELEASE) && *prop->child) {
+ if ((prop->flags & OBJ_PROP_LINK_STRONG) && *prop->child) {
object_unref(*prop->child);
}
g_free(prop);
ObjectProperty *prop = NULL;
GHashTableIter iter;
- g_assert(obj);
- g_assert(obj->parent != NULL);
+ if (obj->parent == NULL) {
+ return NULL;
+ }
g_hash_table_iter_init(&iter, obj->parent->properties);
while (g_hash_table_iter_next(&iter, NULL, (gpointer *)&prop)) {
Object *root = object_get_root();
char *newpath, *path = NULL;
- while (obj != root) {
+ if (obj == root) {
+ return g_strdup("/");
+ }
+
+ do {
char *component = object_get_canonical_path_component(obj);
- if (path) {
- newpath = g_strdup_printf("%s/%s", component, path);
- g_free(component);
+ if (!component) {
+ /* A canonical path must be complete, so discard what was
+ * collected so far.
+ */
g_free(path);
- path = newpath;
- } else {
- path = component;
+ return NULL;
}
+ newpath = g_strdup_printf("/%s%s", component, path ? path : "");
+ g_free(path);
+ g_free(component);
+ path = newpath;
obj = obj->parent;
- }
-
- newpath = g_strdup_printf("/%s", path ? path : "");
- g_free(path);
+ } while (obj != root);
- return newpath;
+ return path;
}
Object *object_resolve_path_component(Object *parent, const gchar *part)
op->description = g_strdup(description);
}
-static void object_instance_init(Object *obj)
+static void object_class_init(ObjectClass *klass, void *data)
{
- object_property_add_str(obj, "type", qdev_get_type, NULL, NULL);
+ object_class_property_add_str(klass, "type", qdev_get_type,
+ NULL, &error_abort);
}
static void register_types(void)
static TypeInfo object_info = {
.name = TYPE_OBJECT,
.instance_size = sizeof(Object),
- .instance_init = object_instance_init,
+ .class_init = object_class_init,
.abstract = true,
};