X-Git-Url: https://repo.jachan.dev/qemu.git/blobdiff_plain/a18bb417e954ceea0a30b46c38b0d58c3a7ca6a1..7746abd8e9ee9db20c0b0fdb19504f163ba3cbea:/qom/object.c diff --git a/qom/object.c b/qom/object.c index b8dff43297..5ff97ab91e 100644 --- a/qom/object.c +++ b/qom/object.c @@ -11,6 +11,7 @@ */ #include "qom/object.h" +#include "qom/object_interfaces.h" #include "qemu-common.h" #include "qapi/visitor.h" #include "qapi-visit.h" @@ -203,7 +204,7 @@ static bool type_is_ancestor(TypeImpl *type, TypeImpl *target_type) { assert(target_type); - /* Check if typename is a direct ancestor of type */ + /* Check if target_type is a direct ancestor of type */ while (type) { if (type == target_type) { return true; @@ -241,6 +242,16 @@ static void type_initialize_interface(TypeImpl *ti, TypeImpl *interface_type, iface_impl->class); } +static void object_property_free(gpointer data) +{ + ObjectProperty *prop = data; + + g_free(prop->name); + g_free(prop->type); + g_free(prop->description); + g_free(prop); +} + static void type_initialize(TypeImpl *ti) { TypeImpl *parent; @@ -260,9 +271,11 @@ static void type_initialize(TypeImpl *ti) GSList *e; int i; - g_assert(parent->class_size <= ti->class_size); + g_assert_cmpint(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_str_hash, g_str_equal, g_free, object_property_free); for (e = parent->class->interfaces; e; e = e->next) { InterfaceClass *iface = e->data; @@ -287,6 +300,9 @@ static void type_initialize(TypeImpl *ti) type_initialize_interface(ti, t, t); } + } else { + ti->class->properties = g_hash_table_new_full( + g_str_hash, g_str_equal, g_free, object_property_free); } ti->class->type = ti; @@ -332,14 +348,15 @@ void object_initialize_with_type(void *data, size_t size, TypeImpl *type) g_assert(type != NULL); type_initialize(type); - g_assert(type->instance_size >= sizeof(Object)); + g_assert_cmpint(type->instance_size, >=, sizeof(Object)); g_assert(type->abstract == false); - g_assert(size >= type->instance_size); + g_assert_cmpint(size, >=, type->instance_size); memset(obj, 0, type->instance_size); obj->class = type->class; object_ref(obj); - QTAILQ_INIT(&obj->properties); + obj->properties = g_hash_table_new_full(g_str_hash, g_str_equal, + NULL, object_property_free); object_init_with_type(obj, type); object_post_init_with_type(obj, type); } @@ -358,29 +375,51 @@ static inline bool object_property_is_child(ObjectProperty *prop) static void object_property_del_all(Object *obj) { - while (!QTAILQ_EMPTY(&obj->properties)) { - ObjectProperty *prop = QTAILQ_FIRST(&obj->properties); - - QTAILQ_REMOVE(&obj->properties, prop, node); - - if (prop->release) { - prop->release(obj, prop->name, prop->opaque); + ObjectProperty *prop; + GHashTableIter iter; + gpointer key, value; + bool released; + + do { + released = false; + g_hash_table_iter_init(&iter, obj->properties); + while (g_hash_table_iter_next(&iter, &key, &value)) { + prop = value; + if (prop->release) { + prop->release(obj, prop->name, prop->opaque); + prop->release = NULL; + released = true; + break; + } + g_hash_table_iter_remove(&iter); } + } while (released); - g_free(prop->name); - g_free(prop->type); - g_free(prop->description); - g_free(prop); - } + g_hash_table_unref(obj->properties); } static void object_property_del_child(Object *obj, Object *child, Error **errp) { ObjectProperty *prop; + GHashTableIter iter; + gpointer key, value; - QTAILQ_FOREACH(prop, &obj->properties, node) { + g_hash_table_iter_init(&iter, obj->properties); + while (g_hash_table_iter_next(&iter, &key, &value)) { + prop = value; + if (object_property_is_child(prop) && prop->opaque == child) { + if (prop->release) { + prop->release(obj, prop->name, prop->opaque); + prop->release = NULL; + } + break; + } + } + g_hash_table_iter_init(&iter, obj->properties); + while (g_hash_table_iter_next(&iter, &key, &value)) { + prop = value; if (object_property_is_child(prop) && prop->opaque == child) { - object_property_del(obj, prop->name, errp); + g_hash_table_iter_remove(&iter); break; } } @@ -412,7 +451,7 @@ static void object_finalize(void *data) object_property_del_all(obj); object_deinit(obj, ti); - g_assert(obj->ref == 0); + g_assert_cmpint(obj->ref, ==, 0); if (obj->free) { obj->free(obj); } @@ -439,6 +478,114 @@ Object *object_new(const char *typename) return object_new_with_type(ti); } + +Object *object_new_with_props(const char *typename, + Object *parent, + const char *id, + Error **errp, + ...) +{ + va_list vargs; + Object *obj; + + va_start(vargs, errp); + obj = object_new_with_propv(typename, parent, id, errp, vargs); + va_end(vargs); + + return obj; +} + + +Object *object_new_with_propv(const char *typename, + Object *parent, + const char *id, + Error **errp, + va_list vargs) +{ + Object *obj; + ObjectClass *klass; + Error *local_err = NULL; + + klass = object_class_by_name(typename); + if (!klass) { + error_setg(errp, "invalid object type: %s", typename); + return NULL; + } + + if (object_class_is_abstract(klass)) { + error_setg(errp, "object type '%s' is abstract", typename); + return NULL; + } + obj = object_new(typename); + + if (object_set_propv(obj, &local_err, vargs) < 0) { + goto error; + } + + object_property_add_child(parent, id, obj, &local_err); + if (local_err) { + goto error; + } + + if (object_dynamic_cast(obj, TYPE_USER_CREATABLE)) { + user_creatable_complete(obj, &local_err); + if (local_err) { + object_unparent(obj); + goto error; + } + } + + object_unref(OBJECT(obj)); + return obj; + + error: + if (local_err) { + error_propagate(errp, local_err); + } + object_unref(obj); + return NULL; +} + + +int object_set_props(Object *obj, + Error **errp, + ...) +{ + va_list vargs; + int ret; + + va_start(vargs, errp); + ret = object_set_propv(obj, errp, vargs); + va_end(vargs); + + return ret; +} + + +int object_set_propv(Object *obj, + Error **errp, + va_list vargs) +{ + const char *propname; + Error *local_err = NULL; + + propname = va_arg(vargs, char *); + while (propname != NULL) { + const char *value = va_arg(vargs, char *); + + g_assert(value != NULL); + object_property_parse(obj, value, propname, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return -1; + } + propname = va_arg(vargs, char *); + } + + return 0; +} + + Object *object_dynamic_cast(Object *obj, const char *typename) { if (obj && object_class_dynamic_cast(object_get_class(obj), typename)) { @@ -666,23 +813,44 @@ void object_class_foreach(void (*fn)(ObjectClass *klass, void *opaque), enumerating_types = false; } -int object_child_foreach(Object *obj, int (*fn)(Object *child, void *opaque), - void *opaque) +static int do_object_child_foreach(Object *obj, + int (*fn)(Object *child, void *opaque), + void *opaque, bool recurse) { - ObjectProperty *prop, *next; + GHashTableIter iter; + ObjectProperty *prop; int ret = 0; - QTAILQ_FOREACH_SAFE(prop, &obj->properties, node, next) { + g_hash_table_iter_init(&iter, obj->properties); + while (g_hash_table_iter_next(&iter, NULL, (gpointer *)&prop)) { if (object_property_is_child(prop)) { - ret = fn(prop->opaque, opaque); + Object *child = prop->opaque; + + ret = fn(child, opaque); if (ret != 0) { break; } + if (recurse) { + do_object_child_foreach(child, fn, opaque, true); + } } } return ret; } +int object_child_foreach(Object *obj, int (*fn)(Object *child, void *opaque), + void *opaque) +{ + return do_object_child_foreach(obj, fn, opaque, false); +} + +int object_child_foreach_recursive(Object *obj, + int (*fn)(Object *child, void *opaque), + void *opaque) +{ + return do_object_child_foreach(obj, fn, opaque, true); +} + static void object_class_get_list_tramp(ObjectClass *klass, void *opaque) { GSList **list = opaque; @@ -705,7 +873,7 @@ void object_ref(Object *obj) if (!obj) { return; } - atomic_inc(&obj->ref); + atomic_inc(&obj->ref); } void object_unref(Object *obj) @@ -713,7 +881,7 @@ void object_unref(Object *obj) if (!obj) { return; } - g_assert(obj->ref > 0); + g_assert_cmpint(obj->ref, >, 0); /* parent always holds a reference to its children */ if (atomic_fetch_dec(&obj->ref) == 1) { @@ -751,13 +919,44 @@ object_property_add(Object *obj, const char *name, const char *type, return ret; } - QTAILQ_FOREACH(prop, &obj->properties, node) { - if (strcmp(prop->name, name) == 0) { - error_setg(errp, "attempt to add duplicate property '%s'" - " to object (type '%s')", name, - object_get_typename(obj)); - return NULL; - } + if (object_property_find(obj, name, NULL) != 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; +} + +ObjectProperty * +object_class_property_add(ObjectClass *klass, + const char *name, + const char *type, + ObjectPropertyAccessor *get, + ObjectPropertyAccessor *set, + ObjectPropertyRelease *release, + void *opaque, + Error **errp) +{ + ObjectProperty *prop; + + if (object_class_property_find(klass, name, NULL) != NULL) { + error_setg(errp, "attempt to add duplicate property '%s'" + " to object (type '%s')", name, + object_class_get_name(klass)); + return NULL; } prop = g_malloc0(sizeof(*prop)); @@ -770,7 +969,8 @@ object_property_add(Object *obj, const char *name, const char *type, prop->release = release; prop->opaque = opaque; - QTAILQ_INSERT_TAIL(&obj->properties, prop, node); + g_hash_table_insert(klass->properties, g_strdup(name), prop); + return prop; } @@ -778,34 +978,76 @@ ObjectProperty *object_property_find(Object *obj, const char *name, Error **errp) { ObjectProperty *prop; + ObjectClass *klass = object_get_class(obj); - QTAILQ_FOREACH(prop, &obj->properties, node) { - if (strcmp(prop->name, name) == 0) { - return prop; - } + prop = object_class_property_find(klass, name, NULL); + if (prop) { + return prop; + } + + prop = g_hash_table_lookup(obj->properties, name); + if (prop) { + return prop; } error_setg(errp, "Property '.%s' not found", name); return NULL; } +void object_property_iter_init(ObjectPropertyIterator *iter, + Object *obj) +{ + g_hash_table_iter_init(&iter->iter, obj->properties); + iter->nextclass = object_get_class(obj); +} + +ObjectProperty *object_property_iter_next(ObjectPropertyIterator *iter) +{ + gpointer key, val; + while (!g_hash_table_iter_next(&iter->iter, &key, &val)) { + if (!iter->nextclass) { + return NULL; + } + g_hash_table_iter_init(&iter->iter, iter->nextclass->properties); + iter->nextclass = object_class_get_parent(iter->nextclass); + } + return val; +} + +ObjectProperty *object_class_property_find(ObjectClass *klass, const char *name, + Error **errp) +{ + ObjectProperty *prop; + ObjectClass *parent_klass; + + parent_klass = object_class_get_parent(klass); + if (parent_klass) { + prop = object_class_property_find(parent_klass, name, NULL); + if (prop) { + return prop; + } + } + + prop = g_hash_table_lookup(klass->properties, name); + if (!prop) { + error_setg(errp, "Property '.%s' not found", name); + } + return prop; +} + void object_property_del(Object *obj, const char *name, Error **errp) { - ObjectProperty *prop = object_property_find(obj, name, errp); - if (prop == NULL) { + ObjectProperty *prop = g_hash_table_lookup(obj->properties, name); + + if (!prop) { + error_setg(errp, "Property '.%s' not found", name); return; } if (prop->release) { prop->release(obj, name, prop->opaque); } - - QTAILQ_REMOVE(&obj->properties, prop, node); - - g_free(prop->name); - g_free(prop->type); - g_free(prop->description); - g_free(prop); + g_hash_table_remove(obj->properties, name); } void object_property_get(Object *obj, Visitor *v, const char *name, @@ -817,7 +1059,7 @@ void object_property_get(Object *obj, Visitor *v, const char *name, } if (!prop->get) { - error_set(errp, QERR_PERMISSION_DENIED); + error_setg(errp, QERR_PERMISSION_DENIED); } else { prop->get(obj, v, prop->opaque, name, errp); } @@ -832,7 +1074,7 @@ void object_property_set(Object *obj, Visitor *v, const char *name, } if (!prop->set) { - error_set(errp, QERR_PERMISSION_DENIED); + error_setg(errp, QERR_PERMISSION_DENIED); } else { prop->set(obj, v, prop->opaque, name, errp); } @@ -859,7 +1101,7 @@ char *object_property_get_str(Object *obj, const char *name, } qstring = qobject_to_qstring(ret); if (!qstring) { - error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "string"); + error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name, "string"); retval = NULL; } else { retval = g_strdup(qstring_get_str(qstring)); @@ -890,7 +1132,8 @@ Object *object_property_get_link(Object *obj, const char *name, if (str && *str) { target = object_resolve_path(str, NULL); if (!target) { - error_set(errp, QERR_DEVICE_NOT_FOUND, str); + error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, + "Device '%s' not found", str); } } @@ -901,7 +1144,7 @@ Object *object_property_get_link(Object *obj, const char *name, void object_property_set_bool(Object *obj, bool value, const char *name, Error **errp) { - QBool *qbool = qbool_from_int(value); + QBool *qbool = qbool_from_bool(value); object_property_set_qobject(obj, QOBJECT(qbool), name, errp); QDECREF(qbool); @@ -919,10 +1162,10 @@ bool object_property_get_bool(Object *obj, const char *name, } qbool = qobject_to_qbool(ret); if (!qbool) { - error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "boolean"); + error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name, "boolean"); retval = false; } else { - retval = qbool_get_int(qbool); + retval = qbool_get_bool(qbool); } QDECREF(qbool); @@ -950,7 +1193,7 @@ int64_t object_property_get_int(Object *obj, const char *name, } qint = qobject_to_qint(ret); if (!qint) { - error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "int"); + error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name, "int"); retval = -1; } else { retval = qint_get_int(qint); @@ -960,21 +1203,48 @@ int64_t object_property_get_int(Object *obj, const char *name, return retval; } +typedef struct EnumProperty { + const char * const *strings; + int (*get)(Object *, Error **); + void (*set)(Object *, int, Error **); +} EnumProperty; + int object_property_get_enum(Object *obj, const char *name, - const char *strings[], Error **errp) + const char *typename, Error **errp) { + Error *err = NULL; StringOutputVisitor *sov; StringInputVisitor *siv; char *str; int ret; + ObjectProperty *prop = object_property_find(obj, name, errp); + EnumProperty *enumprop; + + if (prop == NULL) { + return 0; + } + + if (!g_str_equal(prop->type, typename)) { + error_setg(errp, "Property %s on %s is not '%s' enum type", + name, object_class_get_name( + object_get_class(obj)), typename); + return 0; + } + + enumprop = prop->opaque; sov = string_output_visitor_new(false); - object_property_get(obj, string_output_get_visitor(sov), name, errp); + object_property_get(obj, string_output_get_visitor(sov), name, &err); + if (err) { + error_propagate(errp, err); + string_output_visitor_cleanup(sov); + return 0; + } str = string_output_get_string(sov); siv = string_input_visitor_new(str); string_output_visitor_cleanup(sov); visit_type_enum(string_input_get_visitor(siv), - &ret, strings, NULL, name, errp); + &ret, enumprop->strings, NULL, name, errp); g_free(str); string_input_visitor_cleanup(siv); @@ -985,51 +1255,57 @@ int object_property_get_enum(Object *obj, const char *name, void object_property_get_uint16List(Object *obj, const char *name, uint16List **list, Error **errp) { + Error *err = NULL; StringOutputVisitor *ov; StringInputVisitor *iv; char *str; ov = string_output_visitor_new(false); object_property_get(obj, string_output_get_visitor(ov), - name, errp); + name, &err); + if (err) { + error_propagate(errp, err); + goto out; + } str = string_output_get_string(ov); iv = string_input_visitor_new(str); visit_type_uint16List(string_input_get_visitor(iv), list, NULL, errp); g_free(str); - string_output_visitor_cleanup(ov); string_input_visitor_cleanup(iv); +out: + string_output_visitor_cleanup(ov); } void object_property_parse(Object *obj, const char *string, const char *name, Error **errp) { - StringInputVisitor *mi; - mi = string_input_visitor_new(string); - object_property_set(obj, string_input_get_visitor(mi), name, errp); + StringInputVisitor *siv; + siv = string_input_visitor_new(string); + object_property_set(obj, string_input_get_visitor(siv), name, errp); - string_input_visitor_cleanup(mi); + string_input_visitor_cleanup(siv); } char *object_property_print(Object *obj, const char *name, bool human, Error **errp) { - StringOutputVisitor *mo; + StringOutputVisitor *sov; char *string = NULL; Error *local_err = NULL; - mo = string_output_visitor_new(human); - object_property_get(obj, string_output_get_visitor(mo), name, &local_err); + sov = string_output_visitor_new(human); + object_property_get(obj, string_output_get_visitor(sov), name, &local_err); if (local_err) { error_propagate(errp, local_err); goto out; } - string = string_output_get_string(mo); + string = string_output_get_string(sov); out: - string_output_visitor_cleanup(mo); + string_output_visitor_cleanup(sov); return string; } @@ -1054,6 +1330,11 @@ Object *object_get_root(void) return root; } +Object *object_get_objects_root(void) +{ + return container_get(object_get_root(), "/objects"); +} + static void object_get_child_property(Object *obj, Visitor *v, void *opaque, const char *name, Error **errp) { @@ -1163,14 +1444,15 @@ static Object *object_resolve_link(Object *obj, const char *name, target = object_resolve_path_type(path, target_type, &ambiguous); if (ambiguous) { - error_set(errp, ERROR_CLASS_GENERIC_ERROR, - "Path '%s' does not uniquely identify an object", path); + error_setg(errp, "Path '%s' does not uniquely identify an object", + path); } else if (!target) { target = object_resolve_path(path, &ambiguous); if (target || ambiguous) { - error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, target_type); + error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name, target_type); } else { - error_set(errp, QERR_DEVICE_NOT_FOUND, path); + error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, + "Device '%s' not found", path); } target = NULL; } @@ -1266,14 +1548,32 @@ out: g_free(full_type); } +void object_property_add_const_link(Object *obj, const char *name, + Object *target, Error **errp) +{ + char *link_type; + ObjectProperty *op; + + link_type = g_strdup_printf("link<%s>", object_get_typename(target)); + op = object_property_add(obj, name, link_type, + object_get_child_property, NULL, + NULL, target, errp); + if (op != NULL) { + op->resolve = object_resolve_child_property; + } + g_free(link_type); +} + gchar *object_get_canonical_path_component(Object *obj) { ObjectProperty *prop = NULL; + GHashTableIter iter; g_assert(obj); g_assert(obj->parent != NULL); - QTAILQ_FOREACH(prop, &obj->parent->properties, node) { + g_hash_table_iter_init(&iter, obj->parent->properties); + while (g_hash_table_iter_next(&iter, NULL, (gpointer *)&prop)) { if (!object_property_is_child(prop)) { continue; } @@ -1357,11 +1657,13 @@ static Object *object_resolve_partial_path(Object *parent, bool *ambiguous) { Object *obj; + GHashTableIter iter; ObjectProperty *prop; obj = object_resolve_abs_path(parent, parts, typename, 0); - QTAILQ_FOREACH(prop, &parent->properties, node) { + g_hash_table_iter_init(&iter, parent->properties); + while (g_hash_table_iter_next(&iter, NULL, (gpointer *)&prop)) { Object *found; if (!object_property_is_child(prop)) { @@ -1428,12 +1730,16 @@ static void property_get_str(Object *obj, Visitor *v, void *opaque, { StringProperty *prop = opaque; char *value; + Error *err = NULL; - value = prop->get(obj, errp); - if (value) { - visit_type_str(v, &value, name, errp); - g_free(value); + value = prop->get(obj, &err); + if (err) { + error_propagate(errp, err); + return; } + + visit_type_str(v, &value, name, errp); + g_free(value); } static void property_set_str(Object *obj, Visitor *v, void *opaque, @@ -1482,6 +1788,29 @@ void object_property_add_str(Object *obj, const char *name, } } +void object_class_property_add_str(ObjectClass *klass, const char *name, + char *(*get)(Object *, Error **), + void (*set)(Object *, const char *, + Error **), + Error **errp) +{ + Error *local_err = NULL; + StringProperty *prop = g_malloc0(sizeof(*prop)); + + prop->get = get; + prop->set = set; + + object_class_property_add(klass, name, "string", + get ? property_get_str : NULL, + set ? property_set_str : NULL, + property_release_str, + prop, &local_err); + if (local_err) { + error_propagate(errp, local_err); + g_free(prop); + } +} + typedef struct BoolProperty { bool (*get)(Object *, Error **); @@ -1493,8 +1822,14 @@ static void property_get_bool(Object *obj, Visitor *v, void *opaque, { BoolProperty *prop = opaque; bool value; + Error *err = NULL; + + value = prop->get(obj, &err); + if (err) { + error_propagate(errp, err); + return; + } - value = prop->get(obj, errp); visit_type_bool(v, &value, name, errp); } @@ -1543,6 +1878,116 @@ void object_property_add_bool(Object *obj, const char *name, } } +void object_class_property_add_bool(ObjectClass *klass, const char *name, + bool (*get)(Object *, Error **), + void (*set)(Object *, bool, Error **), + Error **errp) +{ + Error *local_err = NULL; + BoolProperty *prop = g_malloc0(sizeof(*prop)); + + prop->get = get; + prop->set = set; + + object_class_property_add(klass, name, "bool", + get ? property_get_bool : NULL, + set ? property_set_bool : NULL, + property_release_bool, + prop, &local_err); + if (local_err) { + error_propagate(errp, local_err); + g_free(prop); + } +} + +static void property_get_enum(Object *obj, Visitor *v, void *opaque, + const char *name, 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, &value, prop->strings, NULL, name, errp); +} + +static void property_set_enum(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + EnumProperty *prop = opaque; + int value; + Error *err = NULL; + + visit_type_enum(v, &value, prop->strings, NULL, name, &err); + if (err) { + error_propagate(errp, err); + return; + } + prop->set(obj, value, errp); +} + +static void property_release_enum(Object *obj, const char *name, + void *opaque) +{ + EnumProperty *prop = opaque; + g_free(prop); +} + +void object_property_add_enum(Object *obj, const char *name, + const char *typename, + const char * const *strings, + int (*get)(Object *, Error **), + void (*set)(Object *, int, Error **), + Error **errp) +{ + Error *local_err = NULL; + EnumProperty *prop = g_malloc(sizeof(*prop)); + + prop->strings = strings; + prop->get = get; + prop->set = set; + + object_property_add(obj, name, typename, + get ? property_get_enum : NULL, + set ? property_set_enum : NULL, + property_release_enum, + prop, &local_err); + if (local_err) { + error_propagate(errp, local_err); + g_free(prop); + } +} + +void object_class_property_add_enum(ObjectClass *klass, const char *name, + const char *typename, + const char * const *strings, + int (*get)(Object *, Error **), + void (*set)(Object *, int, Error **), + Error **errp) +{ + Error *local_err = NULL; + EnumProperty *prop = g_malloc(sizeof(*prop)); + + prop->strings = strings; + prop->get = get; + prop->set = set; + + object_class_property_add(klass, name, typename, + get ? property_get_enum : NULL, + set ? property_set_enum : NULL, + property_release_enum, + prop, &local_err); + if (local_err) { + error_propagate(errp, local_err); + g_free(prop); + } +} + typedef struct TMProperty { void (*get)(Object *, struct tm *, Error **); } TMProperty; @@ -1622,6 +2067,25 @@ void object_property_add_tm(Object *obj, const char *name, } } +void object_class_property_add_tm(ObjectClass *klass, const char *name, + void (*get)(Object *, struct tm *, Error **), + Error **errp) +{ + Error *local_err = NULL; + TMProperty *prop = g_malloc0(sizeof(*prop)); + + prop->get = get; + + object_class_property_add(klass, name, "struct tm", + get ? property_get_tm : NULL, NULL, + property_release_tm, + prop, &local_err); + if (local_err) { + error_propagate(errp, local_err); + g_free(prop); + } +} + static char *qdev_get_type(Object *obj, Error **errp) { return g_strdup(object_get_typename(obj)); @@ -1666,6 +2130,13 @@ void object_property_add_uint8_ptr(Object *obj, const char *name, NULL, NULL, (void *)v, errp); } +void object_class_property_add_uint8_ptr(ObjectClass *klass, const char *name, + const uint8_t *v, Error **errp) +{ + object_class_property_add(klass, name, "uint8", property_get_uint8_ptr, + NULL, NULL, (void *)v, errp); +} + void object_property_add_uint16_ptr(Object *obj, const char *name, const uint16_t *v, Error **errp) { @@ -1673,6 +2144,13 @@ void object_property_add_uint16_ptr(Object *obj, const char *name, NULL, NULL, (void *)v, errp); } +void object_class_property_add_uint16_ptr(ObjectClass *klass, const char *name, + const uint16_t *v, Error **errp) +{ + object_class_property_add(klass, name, "uint16", property_get_uint16_ptr, + NULL, NULL, (void *)v, errp); +} + void object_property_add_uint32_ptr(Object *obj, const char *name, const uint32_t *v, Error **errp) { @@ -1680,6 +2158,13 @@ void object_property_add_uint32_ptr(Object *obj, const char *name, NULL, NULL, (void *)v, errp); } +void object_class_property_add_uint32_ptr(ObjectClass *klass, const char *name, + const uint32_t *v, Error **errp) +{ + object_class_property_add(klass, name, "uint32", property_get_uint32_ptr, + NULL, NULL, (void *)v, errp); +} + void object_property_add_uint64_ptr(Object *obj, const char *name, const uint64_t *v, Error **errp) { @@ -1687,9 +2172,16 @@ void object_property_add_uint64_ptr(Object *obj, const char *name, NULL, NULL, (void *)v, errp); } +void object_class_property_add_uint64_ptr(ObjectClass *klass, const char *name, + const uint64_t *v, Error **errp) +{ + object_class_property_add(klass, name, "uint64", property_get_uint64_ptr, + NULL, NULL, (void *)v, errp); +} + typedef struct { Object *target_obj; - const char *target_name; + char *target_name; } AliasProperty; static void property_get_alias(Object *obj, struct Visitor *v, void *opaque, @@ -1720,6 +2212,7 @@ static void property_release_alias(Object *obj, const char *name, void *opaque) { AliasProperty *prop = opaque; + g_free(prop->target_name); g_free(prop); } @@ -1747,7 +2240,7 @@ void object_property_add_alias(Object *obj, const char *name, prop = g_malloc(sizeof(*prop)); prop->target_obj = target_obj; - prop->target_name = target_name; + prop->target_name = g_strdup(target_name); op = object_property_add(obj, name, prop_type, property_get_alias, @@ -1783,6 +2276,23 @@ void object_property_set_description(Object *obj, const char *name, op->description = g_strdup(description); } +void object_class_property_set_description(ObjectClass *klass, + const char *name, + const char *description, + Error **errp) +{ + ObjectProperty *op; + + op = g_hash_table_lookup(klass->properties, name); + if (!op) { + error_setg(errp, "Property '.%s' not found", name); + return; + } + + g_free(op->description); + op->description = g_strdup(description); +} + static void object_instance_init(Object *obj) { object_property_add_str(obj, "type", qdev_get_type, NULL, NULL);