Skip to content

Commit

Permalink
qapi: Add feature flags to remaining definitions
Browse files Browse the repository at this point in the history
In v4.1.0, we added feature flags just to struct types (commit
6a8c0b5^..f3ed93d), to satisfy an immediate need (commit
c9d4070 "file-posix: Add dynamic-auto-read-only QAPI feature").  In
v4.2.0, we added them to commands (commit 23394b4 "qapi: Add
feature flags to commands") to satisfy another immediate need (commit
d76744e65e "qapi: Allow introspecting fix for savevm's cooperation
with blockdev").

Add them to the remaining definitions: enumeration types, union types,
alternate types, and events.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-Id: <20200317115459.31821-13-armbru@redhat.com>
  • Loading branch information
Markus Armbruster committed Mar 17, 2020
1 parent e4405b3 commit 013b4ef
Show file tree
Hide file tree
Showing 17 changed files with 242 additions and 121 deletions.
54 changes: 38 additions & 16 deletions docs/devel/qapi-code-gen.txt
Expand Up @@ -172,7 +172,8 @@ Syntax:
ENUM = { 'enum': STRING,
'data': [ ENUM-VALUE, ... ],
'*prefix': STRING,
'*if': COND }
'*if': COND,
'*features': FEATURES }
ENUM-VALUE = STRING
| { 'name': STRING, '*if': COND }

Expand Down Expand Up @@ -207,6 +208,9 @@ the job satisfactorily.
The optional 'if' member specifies a conditional. See "Configuring
the schema" below for more on this.

The optional 'features' member specifies features. See "Features"
below for more on this.


=== Type references and array types ===

Expand Down Expand Up @@ -279,12 +283,14 @@ below for more on this.
Syntax:
UNION = { 'union': STRING,
'data': BRANCHES,
'*if': COND }
'*if': COND,
'*features': FEATURES }
| { 'union': STRING,
'data': BRANCHES,
'base': ( MEMBERS | STRING ),
'discriminator': STRING,
'*if': COND }
'*if': COND,
'*features': FEATURES }
BRANCHES = { BRANCH, ... }
BRANCH = STRING : TYPE-REF
| STRING : { 'type': TYPE-REF, '*if': COND }
Expand Down Expand Up @@ -391,13 +397,17 @@ is identical on the wire to:
The optional 'if' member specifies a conditional. See "Configuring
the schema" below for more on this.

The optional 'features' member specifies features. See "Features"
below for more on this.


=== Alternate types ===

Syntax:
ALTERNATE = { 'alternate': STRING,
'data': ALTERNATIVES,
'*if': COND }
'*if': COND,
'*features': FEATURES }
ALTERNATIVES = { ALTERNATIVE, ... }
ALTERNATIVE = STRING : STRING
| STRING : { 'type': STRING, '*if': COND }
Expand Down Expand Up @@ -441,6 +451,9 @@ following example objects:
The optional 'if' member specifies a conditional. See "Configuring
the schema" below for more on this.

The optional 'features' member specifies features. See "Features"
below for more on this.


=== Commands ===

Expand Down Expand Up @@ -584,6 +597,9 @@ started with --preconfig.
The optional 'if' member specifies a conditional. See "Configuring
the schema" below for more on this.

The optional 'features' member specifies features. See "Features"
below for more on this.


=== Events ===

Expand All @@ -595,7 +611,8 @@ Syntax:
'data': STRING,
'boxed': true,
)
'*if': COND }
'*if': COND,
'*features': FEATURES }

Member 'event' names the event. This is the event name used in the
Client JSON Protocol.
Expand Down Expand Up @@ -628,6 +645,9 @@ complex type. See section "Code generated for events" for examples.
The optional 'if' member specifies a conditional. See "Configuring
the schema" below for more on this.

The optional 'features' member specifies features. See "Features"
below for more on this.


=== Features ===

Expand Down Expand Up @@ -966,8 +986,9 @@ schema, along with the SchemaInfo type. This text attempts to give an
overview how things work. For details you need to consult the QAPI
schema.

SchemaInfo objects have common members "name", "meta-type", and
additional variant members depending on the value of meta-type.
SchemaInfo objects have common members "name", "meta-type",
"features", and additional variant members depending on the value of
meta-type.

Each SchemaInfo object describes a wire ABI entity of a certain
meta-type: a command, event or one of several kinds of type.
Expand All @@ -980,19 +1001,21 @@ not. Therefore, the SchemaInfo for types have auto-generated
meaningless names. For readability, the examples in this section use
meaningful type names instead.

Optional member "features" exposes the entity's feature strings as a
JSON array of strings.

To examine a type, start with a command or event using it, then follow
references by name.

QAPI schema definitions not reachable that way are omitted.

The SchemaInfo for a command has meta-type "command", and variant
members "arg-type", "ret-type", "allow-oob", and "features". On the
wire, the "arguments" member of a client's "execute" command must
conform to the object type named by "arg-type". The "return" member
that the server passes in a success response conforms to the type
named by "ret-type". When "allow-oob" is true, it means the command
supports out-of-band execution. It defaults to false. "features"
exposes the command's feature strings as a JSON array of strings.
members "arg-type", "ret-type" and "allow-oob". On the wire, the
"arguments" member of a client's "execute" command must conform to the
object type named by "arg-type". The "return" member that the server
passes in a success response conforms to the type named by "ret-type".
When "allow-oob" is true, it means the command supports out-of-band
execution. It defaults to false.

If the command takes no arguments, "arg-type" names an object type
without members. Likewise, if the command returns nothing, "ret-type"
Expand Down Expand Up @@ -1027,8 +1050,7 @@ Example: the SchemaInfo for EVENT_C from section Events

The SchemaInfo for struct and union types has meta-type "object".

The SchemaInfo for a struct type has variant members "members" and
"features".
The SchemaInfo for a struct type has variant member "members".

The SchemaInfo for a union type additionally has variant members "tag"
and "variants".
Expand Down
20 changes: 9 additions & 11 deletions qapi/introspect.json
Expand Up @@ -89,12 +89,18 @@
#
# @meta-type: the entity's meta type, inherited from @base.
#
# @features: names of features associated with the entity, in no
# particular order.
# (since 4.1 for object types, 4.2 for commands, 5.0 for
# the rest)
#
# Additional members depend on the value of @meta-type.
#
# Since: 2.5
##
{ 'union': 'SchemaInfo',
'base': { 'name': 'str', 'meta-type': 'SchemaMetaType' },
'base': { 'name': 'str', 'meta-type': 'SchemaMetaType',
'*features': [ 'str' ] },
'discriminator': 'meta-type',
'data': {
'builtin': 'SchemaInfoBuiltin',
Expand Down Expand Up @@ -174,18 +180,14 @@
# and may even differ from the order of the values of the
# enum type of the @tag.
#
# @features: names of features associated with the type, in no particular
# order. (since: 4.1)
#
# Values of this type are JSON object on the wire.
#
# Since: 2.5
##
{ 'struct': 'SchemaInfoObject',
'data': { 'members': [ 'SchemaInfoObjectMember' ],
'*tag': 'str',
'*variants': [ 'SchemaInfoObjectVariant' ],
'*features': [ 'str' ] } }
'*variants': [ 'SchemaInfoObjectVariant' ] } }

##
# @SchemaInfoObjectMember:
Expand Down Expand Up @@ -266,17 +268,13 @@
# @allow-oob: whether the command allows out-of-band execution,
# defaults to false (Since: 2.12)
#
# @features: names of features associated with the command, in no particular
# order. (since 4.2)
#
# TODO: @success-response (currently irrelevant, because it's QGA, not QMP)
#
# Since: 2.5
##
{ 'struct': 'SchemaInfoCommand',
'data': { 'arg-type': 'str', 'ret-type': 'str',
'*allow-oob': 'bool',
'*features': [ 'str' ] } }
'*allow-oob': 'bool' } }

##
# @SchemaInfoEvent:
Expand Down
6 changes: 3 additions & 3 deletions scripts/qapi/doc.py
Expand Up @@ -243,7 +243,7 @@ def __init__(self, prefix):
def write(self, output_dir):
self._gen.write(output_dir)

def visit_enum_type(self, name, info, ifcond, members, prefix):
def visit_enum_type(self, name, info, ifcond, features, members, prefix):
doc = self.cur_doc
self._gen.add(texi_type('Enum', doc, ifcond,
texi_members(doc, 'Values',
Expand All @@ -257,7 +257,7 @@ def visit_object_type(self, name, info, ifcond, base, members, variants,
self._gen.add(texi_type('Object', doc, ifcond,
texi_members(doc, 'Members', base, variants)))

def visit_alternate_type(self, name, info, ifcond, variants):
def visit_alternate_type(self, name, info, ifcond, features, variants):
doc = self.cur_doc
self._gen.add(texi_type('Alternate', doc, ifcond,
texi_members(doc, 'Members')))
Expand All @@ -270,7 +270,7 @@ def visit_command(self, name, info, ifcond, arg_type, ret_type, gen,
texi_arguments(doc,
arg_type if boxed else None)))

def visit_event(self, name, info, ifcond, arg_type, boxed):
def visit_event(self, name, info, ifcond, features, arg_type, boxed):
doc = self.cur_doc
self._gen.add(texi_msg('Event', doc, ifcond,
texi_arguments(doc,
Expand Down
2 changes: 1 addition & 1 deletion scripts/qapi/events.py
Expand Up @@ -189,7 +189,7 @@ def visit_end(self):
event_emit=self._event_emit_name,
event_enum=self._event_enum_name))

def visit_event(self, name, info, ifcond, arg_type, boxed):
def visit_event(self, name, info, ifcond, features, arg_type, boxed):
with ifcontext(ifcond, self._genh, self._genc):
self._genh.add(gen_event_send_decl(name, arg_type, boxed))
self._genc.add(gen_event_send(name, arg_type, boxed,
Expand Down
11 changes: 5 additions & 6 deletions scripts/qapi/expr.py
Expand Up @@ -219,7 +219,6 @@ def check_struct(expr, info):

check_type(members, info, "'data'", allow_dict=name)
check_type(expr.get('base'), info, "'base'")
check_features(expr.get('features'), info)


def check_union(expr, info):
Expand Down Expand Up @@ -267,7 +266,6 @@ def check_command(expr, info):
raise QAPISemError(info, "'boxed': true requires 'data'")
check_type(args, info, "'data'", allow_dict=not boxed)
check_type(rets, info, "'returns'", allow_array=True)
check_features(expr.get('features'), info)


def check_event(expr, info):
Expand Down Expand Up @@ -319,18 +317,18 @@ def check_exprs(exprs):

if meta == 'enum':
check_keys(expr, info, meta,
['enum', 'data'], ['if', 'prefix'])
['enum', 'data'], ['if', 'features', 'prefix'])
check_enum(expr, info)
elif meta == 'union':
check_keys(expr, info, meta,
['union', 'data'],
['base', 'discriminator', 'if'])
['base', 'discriminator', 'if', 'features'])
normalize_members(expr.get('base'))
normalize_members(expr['data'])
check_union(expr, info)
elif meta == 'alternate':
check_keys(expr, info, meta,
['alternate', 'data'], ['if'])
['alternate', 'data'], ['if', 'features'])
normalize_members(expr['data'])
check_alternate(expr, info)
elif meta == 'struct':
Expand All @@ -348,13 +346,14 @@ def check_exprs(exprs):
check_command(expr, info)
elif meta == 'event':
check_keys(expr, info, meta,
['event'], ['data', 'boxed', 'if'])
['event'], ['data', 'boxed', 'if', 'features'])
normalize_members(expr.get('data'))
check_event(expr, info)
else:
assert False, 'unexpected meta type'

check_if(expr, info, meta)
check_features(expr.get('features'), info)
check_flags(expr, info)

return exprs
31 changes: 14 additions & 17 deletions scripts/qapi/introspect.py
Expand Up @@ -144,7 +144,7 @@ def _use_type(self, typ):
return '[' + self._use_type(typ.element_type) + ']'
return self._name(typ.name)

def _gen_qlit(self, name, mtype, obj, ifcond):
def _gen_qlit(self, name, mtype, obj, ifcond, features):
extra = {}
if mtype not in ('command', 'event', 'builtin', 'array'):
if not self._unmask:
Expand All @@ -154,6 +154,8 @@ def _gen_qlit(self, name, mtype, obj, ifcond):
name = self._name(name)
obj['name'] = name
obj['meta-type'] = mtype
if features:
obj['features'] = [(f.name, {'if': f.ifcond}) for f in features]
if ifcond:
extra['if'] = ifcond
if extra:
Expand All @@ -178,35 +180,34 @@ def _gen_variant(self, variant):
{'if': variant.ifcond})

def visit_builtin_type(self, name, info, json_type):
self._gen_qlit(name, 'builtin', {'json-type': json_type}, [])
self._gen_qlit(name, 'builtin', {'json-type': json_type}, [], None)

def visit_enum_type(self, name, info, ifcond, members, prefix):
def visit_enum_type(self, name, info, ifcond, features, members, prefix):
self._gen_qlit(name, 'enum',
{'values':
[(m.name, {'if': m.ifcond}) for m in members]},
ifcond)
ifcond, features)

def visit_array_type(self, name, info, ifcond, element_type):
element = self._use_type(element_type)
self._gen_qlit('[' + element + ']', 'array', {'element-type': element},
ifcond)
ifcond, None)

def visit_object_type_flat(self, name, info, ifcond, members, variants,
features):
obj = {'members': [self._gen_member(m) for m in members]}
if variants:
obj.update(self._gen_variants(variants.tag_member.name,
variants.variants))
if features:
obj['features'] = [(f.name, {'if': f.ifcond}) for f in features]

self._gen_qlit(name, 'object', obj, ifcond)
self._gen_qlit(name, 'object', obj, ifcond, features)

def visit_alternate_type(self, name, info, ifcond, variants):
def visit_alternate_type(self, name, info, ifcond, features, variants):
self._gen_qlit(name, 'alternate',
{'members': [
({'type': self._use_type(m.type)}, {'if': m.ifcond})
for m in variants.variants]}, ifcond)
for m in variants.variants]},
ifcond, features)

def visit_command(self, name, info, ifcond, arg_type, ret_type, gen,
success_response, boxed, allow_oob, allow_preconfig,
Expand All @@ -217,16 +218,12 @@ def visit_command(self, name, info, ifcond, arg_type, ret_type, gen,
'ret-type': self._use_type(ret_type)}
if allow_oob:
obj['allow-oob'] = allow_oob
self._gen_qlit(name, 'command', obj, ifcond, features)

if features:
obj['features'] = [(f.name, {'if': f.ifcond}) for f in features]

self._gen_qlit(name, 'command', obj, ifcond)

def visit_event(self, name, info, ifcond, arg_type, boxed):
def visit_event(self, name, info, ifcond, features, arg_type, boxed):
arg_type = arg_type or self._schema.the_empty_object_type
self._gen_qlit(name, 'event', {'arg-type': self._use_type(arg_type)},
ifcond)
ifcond, features)


def gen_introspect(schema, output_dir, prefix, opt_unmask):
Expand Down

0 comments on commit 013b4ef

Please sign in to comment.