All of lore.kernel.org
 help / color / mirror / Atom feed
From: Markus Armbruster <armbru@redhat.com>
To: Eric Blake <eblake@redhat.com>
Cc: Kevin Wolf <kwolf@redhat.com>,
	Luiz Capitulino <lcapitulino@redhat.com>,
	Michael Roth <mdroth@linux.vnet.ibm.com>,
	"open list:Block layer core" <qemu-block@nongnu.org>,
	qemu-devel@nongnu.org
Subject: Re: [Qemu-devel] [PATCH v11 21/28] qapi: Convert qtype_code into qapi enum type
Date: Thu, 12 Nov 2015 14:16:33 +0100	[thread overview]
Message-ID: <87h9krnyry.fsf@blackfin.pond.sub.org> (raw)
In-Reply-To: <564374D8.7060700@redhat.com> (Eric Blake's message of "Wed, 11 Nov 2015 10:03:20 -0700")

Eric Blake <eblake@redhat.com> writes:

> On 11/11/2015 09:42 AM, Markus Armbruster wrote:
>> Eric Blake <eblake@redhat.com> writes:
>> 
>>> What's more meta than using qapi to define qapi? :)
>>>
>>> Convert qtype_code into a full-fledged[*] builtin qapi enum type,
>>> so that a subsequent patch can then use it as the discriminator
>>> type of qapi alternate types.  Doing so is easiest when renaming
>>> it to qapi conventions, as QTypeCode.
>> 
>> Out of curiosity: why does the rename make the conversion easier?
>
> It guarantees I found all affected instances.  (Although I guess the
> rename could be split to a separate patch from making it builtin).

Well, you have to find them only because you rename, don't you?

> It makes sure that if we later tighten rules about naming, we won't have
> to whitelist 'qtype_code' as an anomaly to our conventions.

Good point.

>> If we rename anyway, what about renaming to QType?  Hmm, we burned that
>> on a struct we use only internally in qobject/.  Oh well.
>
> Internal structs are often easy to rename.  So if we want to avoid the
> need for 'prefix', I could certainly try to achieve that (move internal
> QType out of the way, then rename qtype_code to QType, then make QType
> the builtin).  Looks like this one patch just became three :)

Not sure it's worth the bother; the patch is okay as it is.

QType is overkill.  Instead of

    typedef struct QType {
        qtype_code code;
        void (*destroy)(struct QObject *);
    } QType;

    typedef struct QObject {
        const QType *type;
        size_t refcnt;
    } QObject;

we could simply have

    typedef struct QObject {
        QTypeCode type;
        size_t refcnt;
    } QObject;

with an array mapping QTypeCode to destroy methods.  We're not going to
define additional types at run time.

Perhaps such a change would be actually worth the bother.

>>>                                        Fortunately, there are not
>>> many places in the tree that were actually spelling the type name
>>> out, and the judicious use of 'prefix' in the qapi defintion
>> 
>> definition
>
> I've got to quit coding late at night - my rate of typos increases :)
>
>>> +++ b/docs/qapi-code-gen.txt
>>> @@ -163,6 +163,7 @@ The following types are predefined, and map to C as follows:
>>>                         accepts size suffixes
>>>    bool      bool       JSON true or false
>>>    any       QObject *  any JSON value
>>> +  QTypeCode QTypeCode  JSON string of enum QTypeCode values
>> 
>> QTypeCode is currently used only internally, so the JSON values don't
>> matter.  I don't expect that to change.  However, we either enforce
>> internal use somehow, or document the JSON values.  Documenting them is
>> easier.
>> 
>> In short, your patch is fine.
>> 
>
>>> -
>>> -struct QObject;
>>> +#include "qapi-types.h"
>>>
>>>  typedef struct QType {
>>> -    qtype_code code;
>>> +    QTypeCode code;
>>>      void (*destroy)(struct QObject *);
>>>  } QType;
>>>
>>    typedef struct QObject {
>>        const QType *type;
>>        size_t refcnt;
>>    } QObject;
>> 
>> Note: typedef name QObject still defined here.
>
> Oh, I see what you're saying. Since qapi-types.h now has a forward
> declaration of the QObject typedef, this could be changed to just
>
> struct QObject {
> ...
> };
>
>>> +++ b/scripts/qapi-types.py
>>> @@ -233,8 +233,14 @@ class QAPISchemaGenTypeVisitor(QAPISchemaVisitor):
>>>          self.defn += gen_type_cleanup(name)
>>>
>>>      def visit_enum_type(self, name, info, values, prefix):
>>> -        self._fwdecl += gen_enum(name, values, prefix)
>>> -        self._fwdefn += gen_enum_lookup(name, values, prefix)
>>> +        # Special case for our lone builtin enum type
>>> +        if name == 'QTypeCode':
>> 
>> Would "if not info" work?  Same in qapi-visit.py below.
>
> Feels a bit hacky, since we just recently added is_implicit() to hide
> (and then change) the 'if not info' check on objects.  Maybe an accessor
> is_builtin() makes more sense?  But yes, same approach to both client files.

QAPISchemaEntity methods like is_implicit() or a new is_builtin() can't
work here, because we lack the entity.

We have one in visit_needed(), and we use its is_implicit() to skip
implicit object types.  We could use entity.is_builtin() to skip (some)
builtins, and handle them elsewhere, but that doesn't feel like an
improvement over your code.

Let's take a step back and reconsider how we do builtins.

>> +            self._btin += gen_enum(name, values, prefix)
>> +            if do_builtins:
>> +                self.defn += gen_enum_lookup(name, values, prefix)
>> +        else:
>> +            self._fwdecl += gen_enum(name, values, prefix)
>> +            self._fwdefn += gen_enum_lookup(name, values, prefix)
>>
>>      def visit_array_type(self, name, info, element_type):
>>          if isinstance(element_type, QAPISchemaBuiltinType):

Linking generated code from multiple schemata that share names may fail,
because multiple definitions of the same external symbol exist.

Example: two schemata both define enum BadIdea.  Both generate const
char *BadIdea_lookup[] = { ... }, and we end up with two global symbols
BadIdea_lookup.

Solution: don't do that then.  Easy enough, except *all* schemata share
the builtin symbols!  Solution:

1. For declarations, use ifdeffery to make the compiler ignore all but
   the first copy it encounters,

2. For definitions, make the programmer pick one schema to generate the
   definitions, and run qapi-types.py and qapi-visit.py with -b.

In generator code, this looks like

    self._btin += ... declarations ...
    if do_builtins:
        self.defn += ... definitions ...

instead of the normal

    self.decl += ... declarations ...
    self.defn += ... declarations ...

(or the same with ._fwdecl, ._fwdefn, doesn't matter).

This is why you need to know whether the enum is builtin in
.visit_enum_type() above.

The builtin definitions are emitted into a suitable #ifdef block by
bracketing this code with an initial

    self._btin = guardstart('QAPI_TYPES_BUILTIN')

and a final

    self._btin += guardend('QAPI_TYPES_BUILTIN')
    self.decl = self._btin + self.decl
    self._btin = None

Here's an alternative solution that permits slightly code simpler
generator code, and thus avoids the need to know:

* Generate code for builtins exactly the same as for any other entities,
  i.e. get rid of self._btin and the ifdeffery.

* If the program links just one generated schema, this just works.

* If the program links multiple generated schemata, the programmer has
  to ensure their definitions get generated just once, and their
  declarations are available everywhere anyway.  Straightforward method:

  - The programmer suppresses builtins *completely* for *all* schemata.
    The obvious way to suppress them is to filter them out in
    visit_needed().

  - Instead, he generates them once for the *empty* schema, with a
    well-known --prefix.

  - Suppressing builtins generates a suitable #include for the
    well-known .h with the builtin declarations.

  - Additionally link the .c containing the builtin definitions.

Alternatively, trade some ease-of-use for the single schema case for
ease-of-use for the multiple schemata case and fewer cases:

* The generators either generate for a schema, or they generate builtins.

* When they generate builtins, they always use well-known file names.

* When they generate for a schema, they always generate the #include for
  the well-known builtin .h.  They never generate builtins.

>>> -#include "qapi/qmp/qobject.h"
>>> +
>>> +typedef struct QObject QObject;
>> 
>> Typedef name QObject now also defined here.  GCC accepts this silently
>> without -Wpedantic, but other compilers might not.  Whether we care for
>> such compilers or not, defining things in exactly one place is neater.
>> 
>> Possible fixes:
>> 
>> * Drop the typedef from qobject.h
>> 
>> * Don't add it to qapi-types.h, and use struct QObject there
>> 
>
> I favor dropping the second typedef.

Your choice.

>>> +++ b/scripts/qapi.py
>>> @@ -33,7 +33,7 @@ builtin_types = {
>>>      'uint32':   'QTYPE_QINT',
>>>      'uint64':   'QTYPE_QINT',
>>>      'size':     'QTYPE_QINT',
>>> -    'any':      None,           # any qtype_code possible, actually
>>> +    'any':      None,           # any QTypeCode possible, actually
>>>  }
>>>
>> 
>> Should we list QTypeCode here?
>
> Yeah, probably.  This array is only used by the ad hoc parser, and may
> disappear later as we move more into check(), but we should be
> consistent in the meantime.
>
>> 
>>>  # Whitelist of commands allowed to return a non-dictionary
>>> @@ -1243,6 +1243,11 @@ class QAPISchema(object):
>>>          self.the_empty_object_type = QAPISchemaObjectType(':empty', None, None,
>>>                                                            [], None)
>>>          self._def_entity(self.the_empty_object_type)
>>> +        self._def_entity(QAPISchemaEnumType('QTypeCode', None,
>>> +                                            ['none', 'qnull', 'qint',
>>> +                                             'qstring', 'qdict', 'qlist',
>>> +                                             'qfloat', 'qbool'],
>>> +                                            'QTYPE'))
>>>
>>>      def _make_implicit_enum_type(self, name, info, values):
>>>          name = name + 'Kind'   # Use namespace reserved by add_name()
>> [Trivial changes to expected test output snipped]
>
> I debated about hacking tests/qapi-schema/test-qapi.py to omit QTypeCode
> (the way we already omit builtin types and things like 'intList'), for
> less churn in the .out files.  I can go either way, if you have a
> preference.

Omit them only if it's trivial.

I guess it would be trivial if we adopted the alternative way to do
builtins I sketched above.

  reply	other threads:[~2015-11-12 13:16 UTC|newest]

Thread overview: 72+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-11-11  6:51 [Qemu-devel] [PATCH v11 00/28] qapi member collision, alternate layout (post-introspection cleanups, subset D) Eric Blake
2015-11-11  6:51 ` [Qemu-devel] [PATCH v11 01/28] qapi: Track simple union tag in object.local_members Eric Blake
2015-11-11  6:51 ` [Qemu-devel] [PATCH v11 02/28] qapi-types: Consolidate gen_struct() and gen_union() Eric Blake
2015-11-11  6:51 ` [Qemu-devel] [PATCH v11 03/28] qapi-types: Simplify gen_struct_field[s] Eric Blake
2015-11-11  6:51 ` [Qemu-devel] [PATCH v11 04/28] qapi: Drop obsolete tag value collision assertions Eric Blake
2015-11-11  6:51 ` [Qemu-devel] [PATCH v11 05/28] qapi: Simplify QAPISchemaObjectTypeMember.check() Eric Blake
2015-11-11  6:51 ` [Qemu-devel] [PATCH v11 06/28] qapi: Clean up after previous commit Eric Blake
2015-11-11  6:51 ` [Qemu-devel] [PATCH v11 07/28] qapi: Fix up commit 7618b91's clash sanity checking change Eric Blake
2015-11-11  6:51 ` [Qemu-devel] [PATCH v11 08/28] qapi: Eliminate QAPISchemaObjectType.check() variable members Eric Blake
2015-11-11  6:51 ` [Qemu-devel] [PATCH v11 09/28] qapi: Factor out QAPISchemaObjectTypeMember.check_clash() Eric Blake
2015-11-11  6:51 ` [Qemu-devel] [PATCH v11 10/28] qapi: Simplify QAPISchemaObjectTypeVariants.check() Eric Blake
2015-11-11  6:51 ` [Qemu-devel] [PATCH v11 11/28] qapi: Check for qapi collisions of flat union branches Eric Blake
2015-11-11 13:42   ` Markus Armbruster
2015-11-11 15:49     ` Eric Blake
2015-11-11  6:51 ` [Qemu-devel] [PATCH v11 12/28] qapi: Factor out QAPISchemaObjectType.check_clash() Eric Blake
2015-11-11  6:51 ` [Qemu-devel] [PATCH v11 13/28] qapi: Hoist tag collision check to Variants.check() Eric Blake
2015-11-11 13:56   ` Markus Armbruster
2015-11-11 16:11     ` Eric Blake
2015-11-11 17:03       ` Markus Armbruster
2015-11-11  6:51 ` [Qemu-devel] [PATCH v11 14/28] qapi: Remove outdated tests related to QMP/branch collisions Eric Blake
2015-11-11  6:51 ` [Qemu-devel] [PATCH v11 15/28] qapi: Track owner of each object member Eric Blake
2015-11-11  6:51 ` [Qemu-devel] [PATCH v11 16/28] qapi: Detect collisions in C member names Eric Blake
2015-11-11  6:51 ` [Qemu-devel] [PATCH v11 17/28] cpu: Convert CpuInfo into flat union Eric Blake
2015-11-11 14:13   ` Markus Armbruster
2015-11-11  6:51 ` [Qemu-devel] [PATCH v11 18/28] qerror: more error_setg() usage Eric Blake
2015-11-11 13:26   ` Andreas Färber
2015-11-11 14:21   ` Markus Armbruster
2015-11-11 14:23     ` Andreas Färber
2015-11-11 15:51       ` Eric Blake
2015-11-11 16:19     ` Eric Blake
2015-11-11 17:31       ` Markus Armbruster
2015-11-11 17:44         ` Eric Blake
2015-11-11  6:51 ` [Qemu-devel] [PATCH v11 19/28] qapi: Change munging of CamelCase enum values Eric Blake
2015-11-11 13:29   ` Andreas Färber
2015-11-11 14:50   ` Markus Armbruster
2015-11-11 16:03     ` Eric Blake
2015-11-11 17:11       ` Markus Armbruster
2015-11-12  8:34         ` Gerd Hoffmann
2015-11-12 11:16           ` Markus Armbruster
2015-11-12  8:29       ` Gerd Hoffmann
2015-11-11 16:06     ` Eric Blake
2015-11-13 17:46   ` Eric Blake
2015-11-13 18:13     ` Markus Armbruster
2015-11-13 21:37       ` Eric Blake
2015-11-16 14:30         ` Markus Armbruster
2015-11-11  6:51 ` [Qemu-devel] [PATCH v11 20/28] qapi: Forbid case-insensitive clashes Eric Blake
2015-11-11 14:53   ` Markus Armbruster
2015-11-13  5:32     ` Eric Blake
2015-11-11  6:51 ` [Qemu-devel] [PATCH v11 21/28] qapi: Convert qtype_code into qapi enum type Eric Blake
2015-11-11 16:42   ` Markus Armbruster
2015-11-11 17:03     ` Eric Blake
2015-11-12 13:16       ` Markus Armbruster [this message]
2015-11-18  6:27         ` Eric Blake
2015-11-11  6:51 ` [Qemu-devel] [PATCH v11 22/28] qapi: Simplify visiting of alternate types Eric Blake
2015-11-12 14:21   ` Markus Armbruster
2015-11-12 15:54   ` Markus Armbruster
2015-11-13 23:54   ` Eric Blake
2015-11-16 14:31     ` Markus Armbruster
2015-11-11  6:51 ` [Qemu-devel] [PATCH v11 23/28] qapi: Fix alternates that accept 'number' but not 'int' Eric Blake
2015-11-12 15:01   ` Markus Armbruster
2015-11-11  6:51 ` [Qemu-devel] [PATCH v11 24/28] qapi: Add positive tests to qapi-schema-test Eric Blake
2015-11-11  6:51 ` [Qemu-devel] [PATCH v11 25/28] qapi: Simplify visits of optional fields Eric Blake
2015-11-12 15:11   ` Markus Armbruster
2015-11-12 15:30     ` Eric Blake
2015-11-12 16:20       ` Markus Armbruster
2015-11-11  6:51 ` [Qemu-devel] [PATCH v11 26/28] qapi: Move duplicate member checks to schema check() Eric Blake
2015-11-11  6:51 ` [Qemu-devel] [PATCH v11 27/28] qapi: Move duplicate enum value " Eric Blake
2015-11-12 15:46   ` Markus Armbruster
2015-11-12 16:08     ` Eric Blake
2015-11-18  6:48     ` Eric Blake
2015-11-11  6:51 ` [Qemu-devel] [PATCH v11 28/28] qapi: Detect base class loops Eric Blake
2015-11-12 16:06   ` 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=87h9krnyry.fsf@blackfin.pond.sub.org \
    --to=armbru@redhat.com \
    --cc=eblake@redhat.com \
    --cc=kwolf@redhat.com \
    --cc=lcapitulino@redhat.com \
    --cc=mdroth@linux.vnet.ibm.com \
    --cc=qemu-block@nongnu.org \
    --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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.