Commit 48825ca4 authored by Eric Blake's avatar Eric Blake Committed by Markus Armbruster
Browse files

qapi: Plumb in 'boxed' to qapi generator lower levels



The next patch will add support for passing a qapi union type
as the 'data' of a command.  But to do that, the user function
for implementing the command, as called by the generated
marshal command, must take the corresponding C struct as a
single boxed pointer, rather than a breakdown into one
parameter per member.  Even without a union, being able to use
a C struct rather than a list of parameters can make it much
easier to handle coding with QAPI.

This patch adds the internal plumbing of a 'boxed' flag
associated with each command and event.  In several cases,
this means adding indentation, with one new dead branch and
the remaining branch being the original code more deeply
nested; this was done so that the new implementation in the
next patch is easier to review without also being mixed with
indentation changes.

For this patch, no behavior or generated output changes, other
than the testsuite outputting the value of the new flag
(always False for now).

Signed-off-by: default avatarEric Blake <eblake@redhat.com>
Message-Id: <1468468228-27827-9-git-send-email-eblake@redhat.com>
Reviewed-by: default avatarMarkus Armbruster <armbru@redhat.com>
[Identifier box renamed to boxed in two places]
Signed-off-by: default avatarMarkus Armbruster <armbru@redhat.com>
parent 4d0b268f
Loading
Loading
Loading
Loading
+11 −9
Original line number Diff line number Diff line
@@ -16,20 +16,22 @@ from qapi import *
import re


def gen_command_decl(name, arg_type, ret_type):
def gen_command_decl(name, arg_type, boxed, ret_type):
    return mcgen('''
%(c_type)s qmp_%(c_name)s(%(params)s);
''',
                 c_type=(ret_type and ret_type.c_type()) or 'void',
                 c_name=c_name(name),
                 params=gen_params(arg_type, 'Error **errp'))
                 params=gen_params(arg_type, boxed, 'Error **errp'))


def gen_call(name, arg_type, ret_type):
def gen_call(name, arg_type, boxed, ret_type):
    ret = ''

    argstr = ''
    if arg_type:
    if boxed:
        assert False    # not implemented
    elif arg_type:
        assert not arg_type.variants
        for memb in arg_type.members:
            if memb.optional:
@@ -94,7 +96,7 @@ def gen_marshal_decl(name):
                 proto=gen_marshal_proto(name))


def gen_marshal(name, arg_type, ret_type):
def gen_marshal(name, arg_type, boxed, ret_type):
    ret = mcgen('''

%(proto)s
@@ -136,7 +138,7 @@ def gen_marshal(name, arg_type, ret_type):
    (void)args;
''')

    ret += gen_call(name, arg_type, ret_type)
    ret += gen_call(name, arg_type, boxed, ret_type)

    # 'goto out' produced above for arg_type, and by gen_call() for ret_type
    if (arg_type and not arg_type.is_empty()) or ret_type:
@@ -212,16 +214,16 @@ class QAPISchemaGenCommandVisitor(QAPISchemaVisitor):
        self._visited_ret_types = None

    def visit_command(self, name, info, arg_type, ret_type,
                      gen, success_response):
                      gen, success_response, boxed):
        if not gen:
            return
        self.decl += gen_command_decl(name, arg_type, ret_type)
        self.decl += gen_command_decl(name, arg_type, boxed, ret_type)
        if ret_type and ret_type not in self._visited_ret_types:
            self._visited_ret_types.add(ret_type)
            self.defn += gen_marshal_output(ret_type)
        if middle_mode:
            self.decl += gen_marshal_decl(name)
        self.defn += gen_marshal(name, arg_type, ret_type)
        self.defn += gen_marshal(name, arg_type, boxed, ret_type)
        if not middle_mode:
            self._regy += gen_register_command(name, success_response)

+9 −9
Original line number Diff line number Diff line
@@ -14,18 +14,18 @@
from qapi import *


def gen_event_send_proto(name, arg_type):
def gen_event_send_proto(name, arg_type, boxed):
    return 'void qapi_event_send_%(c_name)s(%(param)s)' % {
        'c_name': c_name(name.lower()),
        'param': gen_params(arg_type, 'Error **errp')}
        'param': gen_params(arg_type, boxed, 'Error **errp')}


def gen_event_send_decl(name, arg_type):
def gen_event_send_decl(name, arg_type, boxed):
    return mcgen('''

%(proto)s;
''',
                 proto=gen_event_send_proto(name, arg_type))
                 proto=gen_event_send_proto(name, arg_type, boxed))


# Declare and initialize an object 'qapi' using parameters from gen_params()
@@ -57,7 +57,7 @@ def gen_param_var(typ):
    return ret


def gen_event_send(name, arg_type):
def gen_event_send(name, arg_type, boxed):
    # FIXME: Our declaration of local variables (and of 'errp' in the
    # parameter list) can collide with exploded members of the event's
    # data type passed in as parameters.  If this collision ever hits in
@@ -72,7 +72,7 @@ def gen_event_send(name, arg_type):
    Error *err = NULL;
    QMPEventFuncEmit emit;
''',
                proto=gen_event_send_proto(name, arg_type))
                proto=gen_event_send_proto(name, arg_type, boxed))

    if arg_type and not arg_type.is_empty():
        ret += mcgen('''
@@ -160,9 +160,9 @@ class QAPISchemaGenEventVisitor(QAPISchemaVisitor):
        self.defn += gen_enum_lookup(event_enum_name, self._event_names)
        self._event_names = None

    def visit_event(self, name, info, arg_type):
        self.decl += gen_event_send_decl(name, arg_type)
        self.defn += gen_event_send(name, arg_type)
    def visit_event(self, name, info, arg_type, boxed):
        self.decl += gen_event_send_decl(name, arg_type, boxed)
        self.defn += gen_event_send(name, arg_type, boxed)
        self._event_names.append(name)


+2 −2
Original line number Diff line number Diff line
@@ -154,14 +154,14 @@ const char %(c_name)s[] = %(c_string)s;
                                    for m in variants.variants]})

    def visit_command(self, name, info, arg_type, ret_type,
                      gen, success_response):
                      gen, success_response, boxed):
        arg_type = arg_type or self._schema.the_empty_object_type
        ret_type = ret_type or self._schema.the_empty_object_type
        self._gen_json(name, 'command',
                       {'arg-type': self._use_type(arg_type),
                        'ret-type': self._use_type(ret_type)})

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

+27 −16
Original line number Diff line number Diff line
@@ -826,10 +826,10 @@ class QAPISchemaVisitor(object):
        pass

    def visit_command(self, name, info, arg_type, ret_type,
                      gen, success_response):
                      gen, success_response, boxed):
        pass

    def visit_event(self, name, info, arg_type):
    def visit_event(self, name, info, arg_type, boxed):
        pass


@@ -1165,7 +1165,8 @@ class QAPISchemaAlternateType(QAPISchemaType):


class QAPISchemaCommand(QAPISchemaEntity):
    def __init__(self, name, info, arg_type, ret_type, gen, success_response):
    def __init__(self, name, info, arg_type, ret_type, gen, success_response,
                 boxed):
        QAPISchemaEntity.__init__(self, name, info)
        assert not arg_type or isinstance(arg_type, str)
        assert not ret_type or isinstance(ret_type, str)
@@ -1175,12 +1176,14 @@ class QAPISchemaCommand(QAPISchemaEntity):
        self.ret_type = None
        self.gen = gen
        self.success_response = success_response
        self.boxed = boxed

    def check(self, schema):
        if self._arg_type_name:
            self.arg_type = schema.lookup_type(self._arg_type_name)
            assert isinstance(self.arg_type, QAPISchemaObjectType)
            assert not self.arg_type.variants   # not implemented
            assert not self.boxed               # not implemented
        if self._ret_type_name:
            self.ret_type = schema.lookup_type(self._ret_type_name)
            assert isinstance(self.ret_type, QAPISchemaType)
@@ -1188,24 +1191,26 @@ class QAPISchemaCommand(QAPISchemaEntity):
    def visit(self, visitor):
        visitor.visit_command(self.name, self.info,
                              self.arg_type, self.ret_type,
                              self.gen, self.success_response)
                              self.gen, self.success_response, self.boxed)


class QAPISchemaEvent(QAPISchemaEntity):
    def __init__(self, name, info, arg_type):
    def __init__(self, name, info, arg_type, boxed):
        QAPISchemaEntity.__init__(self, name, info)
        assert not arg_type or isinstance(arg_type, str)
        self._arg_type_name = arg_type
        self.arg_type = None
        self.boxed = boxed

    def check(self, schema):
        if self._arg_type_name:
            self.arg_type = schema.lookup_type(self._arg_type_name)
            assert isinstance(self.arg_type, QAPISchemaObjectType)
            assert not self.arg_type.variants   # not implemented
            assert not self.boxed               # not implemented

    def visit(self, visitor):
        visitor.visit_event(self.name, self.info, self.arg_type)
        visitor.visit_event(self.name, self.info, self.arg_type, self.boxed)


class QAPISchema(object):
@@ -1381,6 +1386,7 @@ class QAPISchema(object):
        rets = expr.get('returns')
        gen = expr.get('gen', True)
        success_response = expr.get('success-response', True)
        boxed = expr.get('boxed', False)
        if isinstance(data, OrderedDict):
            data = self._make_implicit_object_type(
                name, info, 'arg', self._make_members(data, info))
@@ -1388,15 +1394,16 @@ class QAPISchema(object):
            assert len(rets) == 1
            rets = self._make_array_type(rets[0], info)
        self._def_entity(QAPISchemaCommand(name, info, data, rets, gen,
                                           success_response))
                                           success_response, boxed))

    def _def_event(self, expr, info):
        name = expr['event']
        data = expr.get('data')
        boxed = expr.get('boxed', False)
        if isinstance(data, OrderedDict):
            data = self._make_implicit_object_type(
                name, info, 'arg', self._make_members(data, info))
        self._def_entity(QAPISchemaEvent(name, info, data))
        self._def_entity(QAPISchemaEvent(name, info, data, boxed))

    def _def_exprs(self):
        for expr_elem in self.exprs:
@@ -1639,18 +1646,22 @@ extern const char *const %(c_name)s_lookup[];
    return ret


def gen_params(arg_type, extra):
def gen_params(arg_type, boxed, extra):
    if not arg_type:
        return extra
    assert not arg_type.variants
    ret = ''
    sep = ''
    if boxed:
        assert False     # not implemented
    else:
        assert not arg_type.variants
        for memb in arg_type.members:
            ret += sep
            sep = ', '
            if memb.optional:
                ret += 'bool has_%s, ' % c_name(memb.name)
        ret += '%s %s' % (memb.type.c_param_type(), c_name(memb.name))
            ret += '%s %s' % (memb.type.c_param_type(),
                              c_name(memb.name))
    if extra:
        ret += sep + extra
    return ret
+1 −0
Original line number Diff line number Diff line
enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
    prefix QTYPE
event oops None
   boxed=False
object q_empty
Loading