On Wed, 3 Dec 2025 01:04:54 +0800 Zhao Liu <[email protected]> wrote:
> Now the common (but a bit fragmented) way to mark a property deprecated > is to add the warning in its accssors. > > But this is pretty inconvenient for such qdev properties, which are > defined via DEFINE_PROP_* macros in the Property array. For qdev > properties, their accessors are provided by pre-defined PropertyInfo, so > that it's possible to modify PropertyInfo for a single "deprecated" > property. > > Then it's necessary to introduce property flags to mark some properties > as deprecated, and to check the property flags when set the property, > thereby to print a deprecation warning. > > This not only benefits traditional qdev properties but also helps the > deprecation of generic objects. > > Note, internal attempt (except the compat case) should not trigger the > deprecation warning but external user should see the deprecation > information. Whether to perform deprecation checks based on property > flags is controlled by the newly added "check" argument in > object_property_try_add_full(). I'd split deprecation warning out for this patch, i.e. make this one "add per object instance flags", and take care of deprecation stuff on top, Also, API likely would need set/get/clear calls to operate on object flags. > > In subsequent work, the "check" option will be enabled for specific > external property setting paths. > > Signed-off-by: Zhao Liu <[email protected]> > --- > include/qom/object.h | 72 ++++++++++++++++++++++++++++++++++++++++++++ > qom/object.c | 72 +++++++++++++++++++++++++++++++++++--------- > 2 files changed, 130 insertions(+), 14 deletions(-) > > diff --git a/include/qom/object.h b/include/qom/object.h > index 3f807a03f5aa..8f4c2f44d835 100644 > --- a/include/qom/object.h > +++ b/include/qom/object.h > @@ -86,6 +86,12 @@ typedef void (ObjectPropertyRelease)(Object *obj, > */ > typedef void (ObjectPropertyInit)(Object *obj, ObjectProperty *prop); > > +typedef enum ObjectPropertyFlags { > + OBJECT_PROPERTY_NO_FLAGS = 0, > + OBJECT_PROPERTY_DEPRECATED = 1 << 0, maybe use BIT() instead of manual shift? addidtionally given you are going to distinguish external vs internal, perhaps add flags 'default' and 'user set', I think the both could be used to cleanup cpu flags handling where we rely on setting/checking magic numbers to figure out where value comes from. > + OBJECT_PROPERTY_FULL_FLAGS = OBJECT_PROPERTY_DEPRECATED, > +} ObjectPropertyFlags; > + > struct ObjectProperty > { > char *name; > @@ -98,6 +104,7 @@ struct ObjectProperty > ObjectPropertyInit *init; > void *opaque; > QObject *defval; > + uint8_t flags; > }; > > /** > @@ -1090,6 +1097,41 @@ ObjectProperty *object_property_try_add(Object *obj, > const char *name, > ObjectPropertyRelease *release, > void *opaque, Error **errp); > > +/** > + * object_property_try_add_full: what's the reason for adding _full flavour over just modifying existing API? > + * > + * Same as object_property_try_add() with more arguments (@flags). > + * > + * @obj: the object to add a property to > + * @name: the name of the property. This can contain any character except > for > + * a forward slash. In general, you should use hyphens '-' instead of > + * underscores '_' when naming properties. > + * @type: the type name of the property. This namespace is pretty loosely > + * defined. Sub namespaces are constructed by using a prefix and then > + * to angle brackets. For instance, the type 'virtio-net-pci' in the > + * 'link' namespace would be 'link<virtio-net-pci>'. > + * @get: The getter to be called to read a property. If this is NULL, then > + * the property cannot be read. > + * @set: the setter to be called to write a property. If this is NULL, > + * then the property cannot be written. > + * @release: called when the property is removed from the object. This is > + * meant to allow a property to free its opaque upon object > + * destruction. This may be NULL. > + * @flags: the flags to control property uses. > + * @opaque: an opaque pointer to pass to the callbacks for the property > + * @errp: pointer to error object > + * > + * Returns: The #ObjectProperty; this can be used to set the @resolve > + * callback for child and link properties. > + */ > +ObjectProperty *object_property_try_add_full(Object *obj, const char *name, > + const char *type, > + ObjectPropertyAccessor *get, > + ObjectPropertyAccessor *set, > + ObjectPropertyRelease *release, > + ObjectPropertyFlags flags, > + void *opaque, Error **errp); > + > /** > * object_property_add: > * Same as object_property_try_add() with @errp hardcoded to > @@ -1128,6 +1170,15 @@ ObjectProperty *object_class_property_add(ObjectClass > *klass, const char *name, > ObjectPropertyRelease *release, > void *opaque); > > +ObjectProperty *object_class_property_add_full(ObjectClass *klass, > + const char *name, > + const char *type, > + ObjectPropertyAccessor *get, > + ObjectPropertyAccessor *set, > + ObjectPropertyRelease > *release, > + ObjectPropertyFlags flags, > + void *opaque); > + > /** > * object_property_set_default_bool: > * @prop: the property to set > @@ -1469,6 +1520,27 @@ int object_property_get_enum(Object *obj, const char > *name, > bool object_property_set(Object *obj, const char *name, Visitor *v, > Error **errp); > > +/** > + * object_property_set_full: > + * > + * Same as object_property_set() with extra check over property flags > + * (ObjectPropertyFlags) if @check is true. > + * > + * @obj: the object > + * @name: the name of the property > + * @v: the visitor that will be used to write the property value. This > should > + * be an Input visitor and the data will be first read with @name as the > + * name and then written as the property value. > + * @check: whether to check if the property can be set over property flags. > + * @errp: returns an error if this function fails > + * > + * Writes a property to a object. > + * > + * Returns: %true on success, %false on failure. > + */ > +bool object_property_set_full(Object *obj, const char *name, > + Visitor *v, bool check, Error **errp); > + > /** > * object_property_parse: > * @obj: the object > diff --git a/qom/object.c b/qom/object.c > index 85d31bb64b36..184afc6730dd 100644 > --- a/qom/object.c > +++ b/qom/object.c > @@ -1234,15 +1234,17 @@ void object_unref(void *objptr) > } > > ObjectProperty * > -object_property_try_add(Object *obj, const char *name, const char *type, > - ObjectPropertyAccessor *get, > - ObjectPropertyAccessor *set, > - ObjectPropertyRelease *release, > - void *opaque, Error **errp) > +object_property_try_add_full(Object *obj, const char *name, const char *type, > + ObjectPropertyAccessor *get, > + ObjectPropertyAccessor *set, > + ObjectPropertyRelease *release, > + ObjectPropertyFlags flags, void *opaque, Error > **errp) > { > ObjectProperty *prop; > size_t name_len = strlen(name); > > + assert(!flags || !(flags & ~(OBJECT_PROPERTY_FULL_FLAGS))); > + > if (name_len >= 3 && !memcmp(name + name_len - 3, "[*]", 4)) { > int i; > ObjectProperty *ret = NULL; > @@ -1279,11 +1281,24 @@ object_property_try_add(Object *obj, const char > *name, const char *type, > prop->set = set; > prop->release = release; > prop->opaque = opaque; > + prop->flags = flags; > > g_hash_table_insert(obj->properties, prop->name, prop); > return prop; > } > > +ObjectProperty * > +object_property_try_add(Object *obj, const char *name, const char *type, > + ObjectPropertyAccessor *get, > + ObjectPropertyAccessor *set, > + ObjectPropertyRelease *release, > + void *opaque, Error **errp) > +{ > + return object_property_try_add_full(obj, name, type, get, set, release, > + OBJECT_PROPERTY_NO_FLAGS, opaque, > + errp); > +} > + > ObjectProperty * > object_property_add(Object *obj, const char *name, const char *type, > ObjectPropertyAccessor *get, > @@ -1296,17 +1311,19 @@ object_property_add(Object *obj, const char *name, > const char *type, > } > > ObjectProperty * > -object_class_property_add(ObjectClass *klass, > - const char *name, > - const char *type, > - ObjectPropertyAccessor *get, > - ObjectPropertyAccessor *set, > - ObjectPropertyRelease *release, > - void *opaque) > +object_class_property_add_full(ObjectClass *klass, > + const char *name, > + const char *type, > + ObjectPropertyAccessor *get, > + ObjectPropertyAccessor *set, > + ObjectPropertyRelease *release, > + ObjectPropertyFlags flags, > + void *opaque) > { > ObjectProperty *prop; > > assert(!object_class_property_find(klass, name)); > + assert(!flags || !(flags & ~(OBJECT_PROPERTY_FULL_FLAGS))); > > prop = g_malloc0(sizeof(*prop)); > > @@ -1317,12 +1334,27 @@ object_class_property_add(ObjectClass *klass, > prop->set = set; > prop->release = release; > prop->opaque = opaque; > + prop->flags = flags; > > g_hash_table_insert(klass->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) > +{ > + return object_class_property_add_full(klass, name, type, get, set, > + release, OBJECT_PROPERTY_NO_FLAGS, > + opaque); > +} > + > ObjectProperty *object_property_find(Object *obj, const char *name) > { > ObjectProperty *prop; > @@ -1432,8 +1464,8 @@ bool object_property_get(Object *obj, const char *name, > Visitor *v, > return !err; > } > > -bool object_property_set(Object *obj, const char *name, Visitor *v, > - Error **errp) > +bool object_property_set_full(Object *obj, const char *name, > + Visitor *v, bool check, Error **errp) > { > ERRP_GUARD(); > ObjectProperty *prop = object_property_find_err(obj, name, errp); > @@ -1447,10 +1479,22 @@ bool object_property_set(Object *obj, const char > *name, Visitor *v, > object_get_typename(obj), name); > return false; > } > + > + if (check && prop->flags & OBJECT_PROPERTY_DEPRECATED) { > + warn_report("Property '%s.%s' has been deprecated. " > + "Please do not use it.", object_get_typename(obj), name); > + } > + > prop->set(obj, v, name, prop->opaque, errp); > return !*errp; > } > > +bool object_property_set(Object *obj, const char *name, Visitor *v, > + Error **errp) > +{ > + return object_property_set_full(obj, name, v, false, errp); > +} > + > bool object_property_set_str(Object *obj, const char *name, > const char *value, Error **errp) > {
