qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Eduardo Habkost <ehabkost@redhat.com>
To: Markus Armbruster <armbru@redhat.com>
Cc: "Andreas Färber" <afaerber@suse.de>,
	qemu-devel@nongnu.org, "Paolo Bonzini" <pbonzini@redhat.com>,
	"Lin Ma" <lma@suse.com>
Subject: Re: [Qemu-devel] [PATCH for-2.9 v2] qom: Make all interface types abstract
Date: Wed, 14 Dec 2016 11:48:41 -0200	[thread overview]
Message-ID: <20161214134841.GG3808@thinpad.lan.raisama.net> (raw)
In-Reply-To: <87zijyfyq5.fsf@dusky.pond.sub.org>

On Wed, Dec 14, 2016 at 02:04:50PM +0100, Markus Armbruster wrote:
> Eduardo Habkost <ehabkost@redhat.com> writes:
> 
> > "qom-list-types abstract=false" currently returns all interface
> > types, as if they were not abstract. Fix this by making sure all
> > interface types are abstract.
> >
> > All interface types have instance_size == 0, so we can use
> > it to set abstract=true on type_initialize().
> >
> > Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
> > ---
> > Changes v1 -> v2:
> > * Use old-fashioned if statement instead of "|=" on bool field
> >   Suggested-by: Andreas Färber <afaerber@suse.de>
> > * Keep "device/introspect" path prefix on unit test
> >   * Suggested-by: Andreas Färber <afaerber@suse.de>
> > ---
> >  qom/object.c                   |  6 +++++
> >  tests/device-introspect-test.c | 60 +++++++++++++++++++++++++++++++++++++++---
> >  2 files changed, 63 insertions(+), 3 deletions(-)
> >
> > diff --git a/qom/object.c b/qom/object.c
> > index 7a05e35..760fafb 100644
> > --- a/qom/object.c
> > +++ b/qom/object.c
> > @@ -272,6 +272,12 @@ static void type_initialize(TypeImpl *ti)
> >  
> >      ti->class_size = type_class_get_size(ti);
> >      ti->instance_size = type_object_get_size(ti);
> > +    /* Any type with zero instance_size is implicitly abstract.
> > +     * This means interface types are all abstract.
> > +     */
> > +    if (ti->instance_size == 0) {
> > +        ti->abstract = true;
> > +    }
> >  
> >      ti->class = g_malloc0(ti->class_size);
> >  
> 
> Letting zero instance_size imply abstract works (I guess), but is it
> wise to imply?  Is requiring explicit .abstract = true really too much
> trouble?
> 
> Consider:
> 
>     static const TypeInfo uc_interface_info = {
>         .name          = TYPE_USER_CREATABLE,
>         .parent        = TYPE_INTERFACE,
>         .class_size = sizeof(UserCreatableClass),
>     };
> 
> Is this abstract?  Yes, because there's no .instance_size = ...,
> therefore .instance_size remains zero, and .abstract defaults to true.
> 
>     static const TypeInfo memory_region_info = {
>         .parent             = TYPE_OBJECT,
>         .name               = TYPE_MEMORY_REGION,
>         .instance_size      = sizeof(MemoryRegion),
>         .instance_init      = memory_region_initfn,
>         .instance_finalize  = memory_region_finalize,
>     };
> 
> Is this abstract?  No, because with .instance_size =
> sizeof(MemoryRegion), which known to be non-zero, .abstract defaults to
> false.

Let's make it worse:

static const TypeInfo palmetto_bmc_type = {
    .name = MACHINE_TYPE_NAME("palmetto-bmc"),
    .parent = TYPE_MACHINE,
    .class_init = palmetto_bmc_class_init,
};

Is this abstract? No, because instance_size from the parent type is used, and
it is not zero.

> 
> Is such a complex default a good idea?
> 
>    static const TypeInfo rng_backend_info = {
>        .name = TYPE_RNG_BACKEND,
>        .parent = TYPE_OBJECT,
>        .instance_size = sizeof(RngBackend),
>        .instance_init = rng_backend_init,
>        .instance_finalize = rng_backend_finalize,
>        .class_size = sizeof(RngBackendClass),
>        .class_init = rng_backend_class_init,
>        .abstract = true,
>        .interfaces = (InterfaceInfo[]) {
>            { TYPE_USER_CREATABLE },
>            { }
>        }
>    };
> 
> Is this abstract?  Yes, because with .abstract = true, the default
> doesn't matter.
> 
> How do you find all abstract TypeInfo in the source?  The uninitiated
> might grep for .abstract = true, and be misled.  The initiated will be
> annoyed instead, because grepping for *absence* of .instance_size = is
> bothersome.
> 
> I suspect life could be easier going forward if we instead required
> .abstract = true for interfaces, and enforced it with
> assert(ti->instance_size || ti->abstract) here.

I was doing that before deciding to change type_initialize(). I
think I still have the commit in my git reflog, I will recover it
and submit it as v3.

[...]
> > +static void test_abstract_interfaces(void)
> > +{
> > +    QList *all_types;
> > +    QList *obj_types;
> > +    QListEntry *ae;
> > +
> > +    qtest_start(common_args);
> > +    /* qom-list-types implements=interface would return any type
> > +     * that implements _any_ interface (not just interface types),
> > +     * so use a trick to find the interface type names:
> > +     * - list all object types
> > +     * - list all types, and look for items that are not
> > +     *   on the first list
> > +     */
> > +    all_types = qom_list_types(NULL, false);
> > +    obj_types = qom_list_types("object", false);
> > +
> > +    QLIST_FOREACH_ENTRY(all_types, ae) {
> > +        QDict *at = qobject_to_qdict(qlist_entry_obj(ae));
> > +        const char *aname = qdict_get_str(at, "name");
> > +        QListEntry *oe;
> > +        const char *found = NULL;
> > +
> > +        QLIST_FOREACH_ENTRY(obj_types, oe) {
> > +            QDict *ot = qobject_to_qdict(qlist_entry_obj(oe));
> > +            const char *oname = qdict_get_str(ot, "name");
> > +            if (!strcmp(aname, oname)) {
> > +                found = oname;
> > +                break;
> > +            }
> > +        }
> > +
> > +        /* Using g_assert_cmpstr() will give more useful failure
> > +         * messages than g_assert(found) */
> 
> Sure this comment is worth having?

All we need to check here is if 'found' is not NULL. I think I
would be confused by the usage of g_assert_cmpstr() if I was
reading the code, so I decided to add the comment.

> 
> > +        g_assert_cmpstr(aname, ==, found);
> 
> I'm having a mental block...  what exactly is this loop nest testing?

It's implementing the trick described above:
1) list all object types
2) list all types, and look for items that are not on the first
   list.

In other words, checking if all items in all_types are present in
obj_types.

My first attempt was to just check if
  qom-list-types implements="interface" abstract=false
returned an empty list, but it failed because it returns all
object types that implement any interface.

-- 
Eduardo

  reply	other threads:[~2016-12-14 13:48 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-12-12 18:31 [Qemu-devel] [PATCH for-2.9 v2] qom: Make all interface types abstract Eduardo Habkost
2016-12-14 13:04 ` Markus Armbruster
2016-12-14 13:48   ` Eduardo Habkost [this message]
2016-12-14 17:07     ` Paolo Bonzini
2016-12-14 17:45       ` Eduardo Habkost
2016-12-14 17:47       ` Markus Armbruster
2016-12-15 13:45         ` Paolo Bonzini
2016-12-19 10:21           ` Markus Armbruster

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20161214134841.GG3808@thinpad.lan.raisama.net \
    --to=ehabkost@redhat.com \
    --cc=afaerber@suse.de \
    --cc=armbru@redhat.com \
    --cc=lma@suse.com \
    --cc=pbonzini@redhat.com \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).