Daniel P. Berrangé <berra...@redhat.com> writes:

> When debugging QEMU it is often useful to put a breakpoint on the
> error_setg_internal method impl.
>
> Unfortunately the object_property_add / object_class_property_add
> methods call object_property_find / object_class_property_find methods
> to check if a property exists already before adding the new property.
>
> As a result there are a huge number of calls to error_setg_internal
> on startup of most QEMU commands, making it very painful to set a
> breakpoint on this method.
>
> This puts a minor optimization on the code so that we avoid calling
> error_setg() when errp is NULL. Functionally there's no difference
> since error_setg() is a no-op when errp is NULL, but this lets us
> use breakpoints in GDB in a practical way.
>
> Signed-off-by: Daniel P. Berrangé <berra...@redhat.com>
> ---
>  qom/object.c | 12 ++++++++++--
>  1 file changed, 10 insertions(+), 2 deletions(-)
>
> diff --git a/qom/object.c b/qom/object.c
> index 547dcf97c3..ddd5e7a30e 100644
> --- a/qom/object.c
> +++ b/qom/object.c
> @@ -1087,7 +1087,12 @@ ObjectProperty *object_property_find(Object *obj, 
> const char *name,
>          return prop;
>      }
>  
> -    error_setg(errp, "Property '.%s' not found", name);
> +    /* Optimized to avoid calling error_setg if errp == NULL
> +     * otherwise every property add call hits error_setg
> +     * making it impratical to set breakpoints in GDB */
> +    if (errp) {
> +        error_setg(errp, "Property '.%s' not found", name);
> +    }
>      return NULL;
>  }
>  

In my opinion, this function's design is awkward.  Stress on *opinion*.

On success, it returns a (non-null) pointer.

On failure, it sets an error and returns null.  Note that it has just
one failure mode: "Property '.%s' not found".  Setting an error is just
a convenience for those callers that want to propagate exactly this
error to their callers.

I count 30 callers.  Only six pass a non-NULL argument to @errp.

I'd rather have a pair of functions similar to how Python has both
.get() and .__getitem__(): the former doesn't fail, but returns None
instead, and the latter does fail, throwing KeyError.  In QEMU, we can't
throw, so we set an error.  Here's the obvious code:

    ObjectProperty *object_property_find(Object *obj, const char *name)
    {
        ObjectProperty *prop;
        ObjectClass *klass = object_get_class(obj);

        prop = object_class_property_find(klass, name, NULL);
        if (prop) {
            return prop;
        }

        prop = g_hash_table_lookup(obj->properties, name);
        if (prop) {
            return prop;
        }

        return NULL;
    }

    ObjectProperty *object_property_find_err(Object *obj, const char *name,
                                             Error **errp)
    {
        ObjectProperty *prop = object_property_find(obj, name);

        if (!prop) {
            error_setg(errp, "Property '.%s' not found", name);
        }
        return prop;
    }

> @@ -1133,7 +1138,10 @@ ObjectProperty *object_class_property_find(ObjectClass 
> *klass, const char *name,
>      }
>  
>      prop = g_hash_table_lookup(klass->properties, name);
> -    if (!prop) {
> +    /* Optimized to avoid calling error_setg if errp == NULL
> +     * otherwise every property add call hits error_setg
> +     * making it impratical to set breakpoints in GDB */
> +    if (!prop && errp) {
>          error_setg(errp, "Property '.%s' not found", name);
>      }
>      return prop;

Likewise, just more so: callers passing non-NULL do not exist.

Reply via email to