1fb0bc835SMarkus Armbruster""" 2fb0bc835SMarkus ArmbrusterQAPI command marshaller generator 3fb0bc835SMarkus Armbruster 4fb0bc835SMarkus ArmbrusterCopyright IBM, Corp. 2011 5fb0bc835SMarkus ArmbrusterCopyright (C) 2014-2018 Red Hat, Inc. 6fb0bc835SMarkus Armbruster 7fb0bc835SMarkus ArmbrusterAuthors: 8fb0bc835SMarkus Armbruster Anthony Liguori <aliguori@us.ibm.com> 9fb0bc835SMarkus Armbruster Michael Roth <mdroth@linux.vnet.ibm.com> 10fb0bc835SMarkus Armbruster Markus Armbruster <armbru@redhat.com> 11fb0bc835SMarkus Armbruster 12fb0bc835SMarkus ArmbrusterThis work is licensed under the terms of the GNU GPL, version 2. 13fb0bc835SMarkus ArmbrusterSee the COPYING file in the top-level directory. 14fb0bc835SMarkus Armbruster""" 15fb0bc835SMarkus Armbruster 167304721fSJohn Snowfrom typing import ( 177304721fSJohn Snow Dict, 187304721fSJohn Snow List, 197304721fSJohn Snow Optional, 207304721fSJohn Snow Set, 217304721fSJohn Snow) 227304721fSJohn Snow 23e6a34cd7SJohn Snowfrom .common import c_name, mcgen 24e6a34cd7SJohn Snowfrom .gen import ( 257304721fSJohn Snow QAPIGenC, 26e6a34cd7SJohn Snow QAPIGenCCode, 27e6a34cd7SJohn Snow QAPISchemaModularCVisitor, 28e6a34cd7SJohn Snow build_params, 29e6a34cd7SJohn Snow ifcontext, 30e6a34cd7SJohn Snow) 317304721fSJohn Snowfrom .schema import ( 327304721fSJohn Snow QAPISchema, 337304721fSJohn Snow QAPISchemaFeature, 347304721fSJohn Snow QAPISchemaObjectType, 357304721fSJohn Snow QAPISchemaType, 367304721fSJohn Snow) 377304721fSJohn Snowfrom .source import QAPISourceInfo 38fb0bc835SMarkus Armbruster 39fb0bc835SMarkus Armbruster 407304721fSJohn Snowdef gen_command_decl(name: str, 417304721fSJohn Snow arg_type: Optional[QAPISchemaObjectType], 427304721fSJohn Snow boxed: bool, 437304721fSJohn Snow ret_type: Optional[QAPISchemaType]) -> str: 44fb0bc835SMarkus Armbruster return mcgen(''' 45fb0bc835SMarkus Armbruster%(c_type)s qmp_%(c_name)s(%(params)s); 46fb0bc835SMarkus Armbruster''', 47fb0bc835SMarkus Armbruster c_type=(ret_type and ret_type.c_type()) or 'void', 48fb0bc835SMarkus Armbruster c_name=c_name(name), 49fb0bc835SMarkus Armbruster params=build_params(arg_type, boxed, 'Error **errp')) 50fb0bc835SMarkus Armbruster 51fb0bc835SMarkus Armbruster 527304721fSJohn Snowdef gen_call(name: str, 537304721fSJohn Snow arg_type: Optional[QAPISchemaObjectType], 547304721fSJohn Snow boxed: bool, 557304721fSJohn Snow ret_type: Optional[QAPISchemaType]) -> str: 56fb0bc835SMarkus Armbruster ret = '' 57fb0bc835SMarkus Armbruster 58fb0bc835SMarkus Armbruster argstr = '' 59fb0bc835SMarkus Armbruster if boxed: 60675b214bSMarkus Armbruster assert arg_type 61fb0bc835SMarkus Armbruster argstr = '&arg, ' 62fb0bc835SMarkus Armbruster elif arg_type: 63fb0bc835SMarkus Armbruster assert not arg_type.variants 64fb0bc835SMarkus Armbruster for memb in arg_type.members: 65fb0bc835SMarkus Armbruster if memb.optional: 66fb0bc835SMarkus Armbruster argstr += 'arg.has_%s, ' % c_name(memb.name) 67fb0bc835SMarkus Armbruster argstr += 'arg.%s, ' % c_name(memb.name) 68fb0bc835SMarkus Armbruster 69fb0bc835SMarkus Armbruster lhs = '' 70fb0bc835SMarkus Armbruster if ret_type: 71fb0bc835SMarkus Armbruster lhs = 'retval = ' 72fb0bc835SMarkus Armbruster 73fb0bc835SMarkus Armbruster ret = mcgen(''' 74fb0bc835SMarkus Armbruster 75fb0bc835SMarkus Armbruster %(lhs)sqmp_%(c_name)s(%(args)s&err); 76cdd2b228SMarkus Armbruster error_propagate(errp, err); 77fb0bc835SMarkus Armbruster''', 78fb0bc835SMarkus Armbruster c_name=c_name(name), args=argstr, lhs=lhs) 79fb0bc835SMarkus Armbruster if ret_type: 80fb0bc835SMarkus Armbruster ret += mcgen(''' 81fb0bc835SMarkus Armbruster if (err) { 82fb0bc835SMarkus Armbruster goto out; 83fb0bc835SMarkus Armbruster } 84fb0bc835SMarkus Armbruster 85cdd2b228SMarkus Armbruster qmp_marshal_output_%(c_name)s(retval, ret, errp); 86fb0bc835SMarkus Armbruster''', 87fb0bc835SMarkus Armbruster c_name=ret_type.c_name()) 88fb0bc835SMarkus Armbruster return ret 89fb0bc835SMarkus Armbruster 90fb0bc835SMarkus Armbruster 917304721fSJohn Snowdef gen_marshal_output(ret_type: QAPISchemaType) -> str: 92fb0bc835SMarkus Armbruster return mcgen(''' 93fb0bc835SMarkus Armbruster 9442c0dd12SJohn Snowstatic void qmp_marshal_output_%(c_name)s(%(c_type)s ret_in, 9542c0dd12SJohn Snow QObject **ret_out, Error **errp) 96fb0bc835SMarkus Armbruster{ 97fb0bc835SMarkus Armbruster Visitor *v; 98fb0bc835SMarkus Armbruster 99fb0bc835SMarkus Armbruster v = qobject_output_visitor_new(ret_out); 100cdd2b228SMarkus Armbruster if (visit_type_%(c_name)s(v, "unused", &ret_in, errp)) { 101fb0bc835SMarkus Armbruster visit_complete(v, ret_out); 102fb0bc835SMarkus Armbruster } 103fb0bc835SMarkus Armbruster visit_free(v); 104fb0bc835SMarkus Armbruster v = qapi_dealloc_visitor_new(); 105fb0bc835SMarkus Armbruster visit_type_%(c_name)s(v, "unused", &ret_in, NULL); 106fb0bc835SMarkus Armbruster visit_free(v); 107fb0bc835SMarkus Armbruster} 108fb0bc835SMarkus Armbruster''', 109fb0bc835SMarkus Armbruster c_type=ret_type.c_type(), c_name=ret_type.c_name()) 110fb0bc835SMarkus Armbruster 111fb0bc835SMarkus Armbruster 1127304721fSJohn Snowdef build_marshal_proto(name: str) -> str: 113fb0bc835SMarkus Armbruster return ('void qmp_marshal_%s(QDict *args, QObject **ret, Error **errp)' 114fb0bc835SMarkus Armbruster % c_name(name)) 115fb0bc835SMarkus Armbruster 116fb0bc835SMarkus Armbruster 1177304721fSJohn Snowdef gen_marshal_decl(name: str) -> str: 118fb0bc835SMarkus Armbruster return mcgen(''' 119fb0bc835SMarkus Armbruster%(proto)s; 120fb0bc835SMarkus Armbruster''', 121fb0bc835SMarkus Armbruster proto=build_marshal_proto(name)) 122fb0bc835SMarkus Armbruster 123fb0bc835SMarkus Armbruster 1247304721fSJohn Snowdef gen_marshal(name: str, 1257304721fSJohn Snow arg_type: Optional[QAPISchemaObjectType], 1267304721fSJohn Snow boxed: bool, 1277304721fSJohn Snow ret_type: Optional[QAPISchemaType]) -> str: 128675b214bSMarkus Armbruster have_args = boxed or (arg_type and not arg_type.is_empty()) 129*ec9697abSJohn Snow if have_args: 130*ec9697abSJohn Snow assert arg_type is not None 131*ec9697abSJohn Snow arg_type_c_name = arg_type.c_name() 132fb0bc835SMarkus Armbruster 133fb0bc835SMarkus Armbruster ret = mcgen(''' 134fb0bc835SMarkus Armbruster 135fb0bc835SMarkus Armbruster%(proto)s 136fb0bc835SMarkus Armbruster{ 137fb0bc835SMarkus Armbruster Error *err = NULL; 138cdd2b228SMarkus Armbruster bool ok = false; 1392061487bSMarkus Armbruster Visitor *v; 140fb0bc835SMarkus Armbruster''', 141fb0bc835SMarkus Armbruster proto=build_marshal_proto(name)) 142fb0bc835SMarkus Armbruster 143fb0bc835SMarkus Armbruster if ret_type: 144fb0bc835SMarkus Armbruster ret += mcgen(''' 145fb0bc835SMarkus Armbruster %(c_type)s retval; 146fb0bc835SMarkus Armbruster''', 147fb0bc835SMarkus Armbruster c_type=ret_type.c_type()) 148fb0bc835SMarkus Armbruster 149fb0bc835SMarkus Armbruster if have_args: 150fb0bc835SMarkus Armbruster ret += mcgen(''' 151fb0bc835SMarkus Armbruster %(c_name)s arg = {0}; 152fb0bc835SMarkus Armbruster''', 153*ec9697abSJohn Snow c_name=arg_type_c_name) 154fb0bc835SMarkus Armbruster 155fb0bc835SMarkus Armbruster ret += mcgen(''' 1562061487bSMarkus Armbruster 157fb0bc835SMarkus Armbruster v = qobject_input_visitor_new(QOBJECT(args)); 158cdd2b228SMarkus Armbruster if (!visit_start_struct(v, NULL, NULL, 0, errp)) { 159fb0bc835SMarkus Armbruster goto out; 160fb0bc835SMarkus Armbruster } 16189bf68f9SMarkus Armbruster''') 16289bf68f9SMarkus Armbruster 16389bf68f9SMarkus Armbruster if have_args: 16489bf68f9SMarkus Armbruster ret += mcgen(''' 165cdd2b228SMarkus Armbruster if (visit_type_%(c_arg_type)s_members(v, &arg, errp)) { 166cdd2b228SMarkus Armbruster ok = visit_check_struct(v, errp); 167fb0bc835SMarkus Armbruster } 16889bf68f9SMarkus Armbruster''', 169*ec9697abSJohn Snow c_arg_type=arg_type_c_name) 17089bf68f9SMarkus Armbruster else: 17189bf68f9SMarkus Armbruster ret += mcgen(''' 172cdd2b228SMarkus Armbruster ok = visit_check_struct(v, errp); 17389bf68f9SMarkus Armbruster''') 17489bf68f9SMarkus Armbruster 17589bf68f9SMarkus Armbruster ret += mcgen(''' 176fb0bc835SMarkus Armbruster visit_end_struct(v, NULL); 177cdd2b228SMarkus Armbruster if (!ok) { 178fb0bc835SMarkus Armbruster goto out; 179fb0bc835SMarkus Armbruster } 18089bf68f9SMarkus Armbruster''') 181fb0bc835SMarkus Armbruster 182fb0bc835SMarkus Armbruster ret += gen_call(name, arg_type, boxed, ret_type) 183fb0bc835SMarkus Armbruster 184fb0bc835SMarkus Armbruster ret += mcgen(''' 185fb0bc835SMarkus Armbruster 186fb0bc835SMarkus Armbrusterout: 187fb0bc835SMarkus Armbruster visit_free(v); 188fb0bc835SMarkus Armbruster''') 189fb0bc835SMarkus Armbruster 190fb0bc835SMarkus Armbruster ret += mcgen(''' 191fb0bc835SMarkus Armbruster v = qapi_dealloc_visitor_new(); 192fb0bc835SMarkus Armbruster visit_start_struct(v, NULL, NULL, 0, NULL); 19389bf68f9SMarkus Armbruster''') 19489bf68f9SMarkus Armbruster 19589bf68f9SMarkus Armbruster if have_args: 19689bf68f9SMarkus Armbruster ret += mcgen(''' 19789bf68f9SMarkus Armbruster visit_type_%(c_arg_type)s_members(v, &arg, NULL); 19889bf68f9SMarkus Armbruster''', 199*ec9697abSJohn Snow c_arg_type=arg_type_c_name) 20089bf68f9SMarkus Armbruster 20189bf68f9SMarkus Armbruster ret += mcgen(''' 202fb0bc835SMarkus Armbruster visit_end_struct(v, NULL); 203fb0bc835SMarkus Armbruster visit_free(v); 20489bf68f9SMarkus Armbruster''') 205fb0bc835SMarkus Armbruster 206fb0bc835SMarkus Armbruster ret += mcgen(''' 207fb0bc835SMarkus Armbruster} 208fb0bc835SMarkus Armbruster''') 209fb0bc835SMarkus Armbruster return ret 210fb0bc835SMarkus Armbruster 211fb0bc835SMarkus Armbruster 2127304721fSJohn Snowdef gen_register_command(name: str, 2137304721fSJohn Snow success_response: bool, 2147304721fSJohn Snow allow_oob: bool, 2157304721fSJohn Snow allow_preconfig: bool, 2167304721fSJohn Snow coroutine: bool) -> str: 217876c6751SPeter Xu options = [] 218876c6751SPeter Xu 219fb0bc835SMarkus Armbruster if not success_response: 220876c6751SPeter Xu options += ['QCO_NO_SUCCESS_RESP'] 221876c6751SPeter Xu if allow_oob: 222876c6751SPeter Xu options += ['QCO_ALLOW_OOB'] 223d6fe3d02SIgor Mammedov if allow_preconfig: 224d6fe3d02SIgor Mammedov options += ['QCO_ALLOW_PRECONFIG'] 22504f22362SKevin Wolf if coroutine: 22604f22362SKevin Wolf options += ['QCO_COROUTINE'] 227876c6751SPeter Xu 228876c6751SPeter Xu if not options: 229876c6751SPeter Xu options = ['QCO_NO_OPTIONS'] 230876c6751SPeter Xu 231fb0bc835SMarkus Armbruster ret = mcgen(''' 232fb0bc835SMarkus Armbruster qmp_register_command(cmds, "%(name)s", 233fb0bc835SMarkus Armbruster qmp_marshal_%(c_name)s, %(opts)s); 234fb0bc835SMarkus Armbruster''', 235fb0bc835SMarkus Armbruster name=name, c_name=c_name(name), 236ab2d8a75SJohn Snow opts=" | ".join(options)) 237fb0bc835SMarkus Armbruster return ret 238fb0bc835SMarkus Armbruster 239fb0bc835SMarkus Armbruster 2407304721fSJohn Snowdef gen_registry(registry: str, prefix: str) -> str: 241fb0bc835SMarkus Armbruster ret = mcgen(''' 242fb0bc835SMarkus Armbruster 243fb0bc835SMarkus Armbrustervoid %(c_prefix)sqmp_init_marshal(QmpCommandList *cmds) 244fb0bc835SMarkus Armbruster{ 245fb0bc835SMarkus Armbruster QTAILQ_INIT(cmds); 246fb0bc835SMarkus Armbruster 247fb0bc835SMarkus Armbruster''', 248fb0bc835SMarkus Armbruster c_prefix=c_name(prefix, protect=False)) 249fb0bc835SMarkus Armbruster ret += registry 250fb0bc835SMarkus Armbruster ret += mcgen(''' 251fb0bc835SMarkus Armbruster} 252fb0bc835SMarkus Armbruster''') 253fb0bc835SMarkus Armbruster return ret 254fb0bc835SMarkus Armbruster 255fb0bc835SMarkus Armbruster 256252dc310SMarkus Armbrusterclass QAPISchemaGenCommandVisitor(QAPISchemaModularCVisitor): 2577304721fSJohn Snow def __init__(self, prefix: str): 2582cae67bcSMarkus Armbruster super().__init__( 2592cae67bcSMarkus Armbruster prefix, 'qapi-commands', 2603bef3aaeSMarkus Armbruster ' * Schema-defined QAPI/QMP commands', None, __doc__) 261dddee4d7SMarkus Armbruster self._regy = QAPIGenCCode(None) 2627304721fSJohn Snow self._visited_ret_types: Dict[QAPIGenC, Set[QAPISchemaType]] = {} 263252dc310SMarkus Armbruster 2647304721fSJohn Snow def _begin_user_module(self, name: str) -> None: 265252dc310SMarkus Armbruster self._visited_ret_types[self._genc] = set() 2669af23989SMarkus Armbruster commands = self._module_basename('qapi-commands', name) 2679af23989SMarkus Armbruster types = self._module_basename('qapi-types', name) 2689af23989SMarkus Armbruster visit = self._module_basename('qapi-visit', name) 26971b3f045SMarkus Armbruster self._genc.add(mcgen(''' 270fb0bc835SMarkus Armbruster#include "qemu/osdep.h" 271fb0bc835SMarkus Armbruster#include "qapi/visitor.h" 272fb0bc835SMarkus Armbruster#include "qapi/qmp/qdict.h" 273fb0bc835SMarkus Armbruster#include "qapi/qobject-output-visitor.h" 274fb0bc835SMarkus Armbruster#include "qapi/qobject-input-visitor.h" 275fb0bc835SMarkus Armbruster#include "qapi/dealloc-visitor.h" 276fb0bc835SMarkus Armbruster#include "qapi/error.h" 2779af23989SMarkus Armbruster#include "%(visit)s.h" 2789af23989SMarkus Armbruster#include "%(commands)s.h" 279fb0bc835SMarkus Armbruster 280fb0bc835SMarkus Armbruster''', 2819af23989SMarkus Armbruster commands=commands, visit=visit)) 28271b3f045SMarkus Armbruster self._genh.add(mcgen(''' 2839af23989SMarkus Armbruster#include "%(types)s.h" 284fb0bc835SMarkus Armbruster 285fb0bc835SMarkus Armbruster''', 2869af23989SMarkus Armbruster types=types)) 287fb0bc835SMarkus Armbruster 2887304721fSJohn Snow def visit_end(self) -> None: 28900ca24ffSMarkus Armbruster self._add_system_module('init', ' * QAPI Commands initialization') 29000ca24ffSMarkus Armbruster self._genh.add(mcgen(''' 29100ca24ffSMarkus Armbruster#include "qapi/qmp/dispatch.h" 29200ca24ffSMarkus Armbruster 293252dc310SMarkus Armbrustervoid %(c_prefix)sqmp_init_marshal(QmpCommandList *cmds); 294252dc310SMarkus Armbruster''', 295252dc310SMarkus Armbruster c_prefix=c_name(self._prefix, protect=False))) 29600ca24ffSMarkus Armbruster self._genc.preamble_add(mcgen(''' 29700ca24ffSMarkus Armbruster#include "qemu/osdep.h" 29800ca24ffSMarkus Armbruster#include "%(prefix)sqapi-commands.h" 29900ca24ffSMarkus Armbruster#include "%(prefix)sqapi-init-commands.h" 30000ca24ffSMarkus Armbruster''', 30100ca24ffSMarkus Armbruster prefix=self._prefix)) 30200ca24ffSMarkus Armbruster self._genc.add(gen_registry(self._regy.get_content(), self._prefix)) 30371b3f045SMarkus Armbruster 3047304721fSJohn Snow def visit_command(self, 3057304721fSJohn Snow name: str, 3067304721fSJohn Snow info: QAPISourceInfo, 3077304721fSJohn Snow ifcond: List[str], 3087304721fSJohn Snow features: List[QAPISchemaFeature], 3097304721fSJohn Snow arg_type: Optional[QAPISchemaObjectType], 3107304721fSJohn Snow ret_type: Optional[QAPISchemaType], 3117304721fSJohn Snow gen: bool, 3127304721fSJohn Snow success_response: bool, 3137304721fSJohn Snow boxed: bool, 3147304721fSJohn Snow allow_oob: bool, 3157304721fSJohn Snow allow_preconfig: bool, 3167304721fSJohn Snow coroutine: bool) -> None: 31771b3f045SMarkus Armbruster if not gen: 31871b3f045SMarkus Armbruster return 3191f7b9f31SMarc-André Lureau # FIXME: If T is a user-defined type, the user is responsible 3201f7b9f31SMarc-André Lureau # for making this work, i.e. to make T's condition the 3211f7b9f31SMarc-André Lureau # conjunction of the T-returning commands' conditions. If T 3221f7b9f31SMarc-André Lureau # is a built-in type, this isn't possible: the 3231f7b9f31SMarc-André Lureau # qmp_marshal_output_T() will be generated unconditionally. 324252dc310SMarkus Armbruster if ret_type and ret_type not in self._visited_ret_types[self._genc]: 325252dc310SMarkus Armbruster self._visited_ret_types[self._genc].add(ret_type) 3261f7b9f31SMarc-André Lureau with ifcontext(ret_type.ifcond, 3271f7b9f31SMarc-André Lureau self._genh, self._genc, self._regy): 32871b3f045SMarkus Armbruster self._genc.add(gen_marshal_output(ret_type)) 3291f7b9f31SMarc-André Lureau with ifcontext(ifcond, self._genh, self._genc, self._regy): 3301f7b9f31SMarc-André Lureau self._genh.add(gen_command_decl(name, arg_type, boxed, ret_type)) 33171b3f045SMarkus Armbruster self._genh.add(gen_marshal_decl(name)) 33271b3f045SMarkus Armbruster self._genc.add(gen_marshal(name, arg_type, boxed, ret_type)) 3331f7b9f31SMarc-André Lureau self._regy.add(gen_register_command(name, success_response, 33404f22362SKevin Wolf allow_oob, allow_preconfig, 33504f22362SKevin Wolf coroutine)) 33671b3f045SMarkus Armbruster 33771b3f045SMarkus Armbruster 3387304721fSJohn Snowdef gen_commands(schema: QAPISchema, 3397304721fSJohn Snow output_dir: str, 3407304721fSJohn Snow prefix: str) -> None: 341fb0bc835SMarkus Armbruster vis = QAPISchemaGenCommandVisitor(prefix) 342fb0bc835SMarkus Armbruster schema.visit(vis) 34371b3f045SMarkus Armbruster vis.write(output_dir) 344