diff options
Diffstat (limited to 'scripts')
-rw-r--r-- | scripts/qapi-commands.py | 91 | ||||
-rw-r--r-- | scripts/qapi-visit.py | 232 | ||||
-rw-r--r-- | scripts/qapi.py | 16 |
3 files changed, 200 insertions, 139 deletions
diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py index 8d9096f65c..7d93d01ed2 100644 --- a/scripts/qapi-commands.py +++ b/scripts/qapi-commands.py @@ -2,16 +2,19 @@ # QAPI command marshaller generator # # Copyright IBM, Corp. 2011 +# Copyright (C) 2014 Red Hat, Inc. # # Authors: # Anthony Liguori <aliguori@us.ibm.com> # Michael Roth <mdroth@linux.vnet.ibm.com> +# Markus Armbruster <armbru@redhat.com> # # This work is licensed under the terms of the GNU GPL, version 2. # See the COPYING file in the top-level directory. from ordereddict import OrderedDict from qapi import * +import re import sys import os import getopt @@ -37,6 +40,15 @@ def generate_command_decl(name, args, ret_type): ''', ret_type=c_type(ret_type), name=c_fun(name), args=arglist).strip() +def gen_err_check(errvar): + if errvar: + return mcgen(''' +if (local_err) { + goto out; +} +''') + return '' + def gen_sync_call(name, args, ret_type, indent=0): ret = "" arglist="" @@ -49,15 +61,14 @@ def gen_sync_call(name, args, ret_type, indent=0): arglist += "%s, " % (c_var(argname)) push_indent(indent) ret = mcgen(''' -%(retval)sqmp_%(name)s(%(args)serrp); +%(retval)sqmp_%(name)s(%(args)s&local_err); ''', name=c_fun(name), args=arglist, retval=retval).rstrip() if ret_type: + ret += "\n" + gen_err_check('local_err') ret += "\n" + mcgen('''' -if (!error_is_set(errp)) { - %(marshal_output_call)s -} +%(marshal_output_call)s ''', marshal_output_call=gen_marshal_output_call(name, ret_type)).rstrip() pop_indent(indent) @@ -67,18 +78,19 @@ if (!error_is_set(errp)) { def gen_marshal_output_call(name, ret_type): if not ret_type: return "" - return "qmp_marshal_output_%s(retval, ret, errp);" % c_fun(name) + return "qmp_marshal_output_%s(retval, ret, &local_err);" % c_fun(name) -def gen_visitor_input_containers_decl(args): +def gen_visitor_input_containers_decl(args, obj): ret = "" push_indent() if len(args) > 0: ret += mcgen(''' -QmpInputVisitor *mi; +QmpInputVisitor *mi = qmp_input_visitor_new_strict(%(obj)s); QapiDeallocVisitor *md; Visitor *v; -''') +''', + obj=obj) pop_indent() return ret.rstrip() @@ -99,16 +111,17 @@ bool has_%(argname)s = false; argname=c_var(argname), argtype=c_type(argtype)) else: ret += mcgen(''' -%(argtype)s %(argname)s; +%(argtype)s %(argname)s = {0}; ''', argname=c_var(argname), argtype=c_type(argtype)) pop_indent() return ret.rstrip() -def gen_visitor_input_block(args, obj, dealloc=False): +def gen_visitor_input_block(args, dealloc=False): ret = "" - errparg = 'errp' + errparg = '&local_err' + errarg = 'local_err' if len(args) == 0: return ret @@ -117,45 +130,45 @@ def gen_visitor_input_block(args, obj, dealloc=False): if dealloc: errparg = 'NULL' + errarg = None; ret += mcgen(''' +qmp_input_visitor_cleanup(mi); md = qapi_dealloc_visitor_new(); v = qapi_dealloc_get_visitor(md); ''') else: ret += mcgen(''' -mi = qmp_input_visitor_new_strict(%(obj)s); v = qmp_input_get_visitor(mi); -''', - obj=obj) +''') for argname, argtype, optional, structured in parse_args(args): if optional: ret += mcgen(''' -visit_start_optional(v, &has_%(c_name)s, "%(name)s", %(errp)s); -if (has_%(c_name)s) { +visit_optional(v, &has_%(c_name)s, "%(name)s", %(errp)s); ''', c_name=c_var(argname), name=argname, errp=errparg) + ret += gen_err_check(errarg) + ret += mcgen(''' +if (has_%(c_name)s) { +''', + c_name=c_var(argname)) push_indent() ret += mcgen(''' %(visitor)s(v, &%(c_name)s, "%(name)s", %(errp)s); ''', c_name=c_var(argname), name=argname, argtype=argtype, visitor=type_visitor(argtype), errp=errparg) + ret += gen_err_check(errarg) if optional: pop_indent() ret += mcgen(''' } -visit_end_optional(v, %(errp)s); -''', errp=errparg) +''') if dealloc: ret += mcgen(''' qapi_dealloc_visitor_cleanup(md); ''') - else: - ret += mcgen(''' -qmp_input_visitor_cleanup(mi); -''') pop_indent() return ret.rstrip() @@ -166,16 +179,22 @@ def gen_marshal_output(name, args, ret_type, middle_mode): ret = mcgen(''' static void qmp_marshal_output_%(c_name)s(%(c_ret_type)s ret_in, QObject **ret_out, Error **errp) { - QapiDeallocVisitor *md = qapi_dealloc_visitor_new(); + Error *local_err = NULL; QmpOutputVisitor *mo = qmp_output_visitor_new(); + QapiDeallocVisitor *md; Visitor *v; v = qmp_output_get_visitor(mo); - %(visitor)s(v, &ret_in, "unused", errp); - if (!error_is_set(errp)) { - *ret_out = qmp_output_get_qobject(mo); + %(visitor)s(v, &ret_in, "unused", &local_err); + if (local_err) { + goto out; } + *ret_out = qmp_output_get_qobject(mo); + +out: + error_propagate(errp, local_err); qmp_output_visitor_cleanup(mo); + md = qapi_dealloc_visitor_new(); v = qapi_dealloc_get_visitor(md); %(visitor)s(v, &ret_in, "unused", NULL); qapi_dealloc_visitor_cleanup(md); @@ -200,13 +219,12 @@ def gen_marshal_input(name, args, ret_type, middle_mode): ret = mcgen(''' %(header)s { + Error *local_err = NULL; ''', header=hdr) if middle_mode: ret += mcgen(''' - Error *local_err = NULL; - Error **errp = &local_err; QDict *args = (QDict *)qdict; ''') @@ -228,29 +246,32 @@ def gen_marshal_input(name, args, ret_type, middle_mode): %(visitor_input_block)s ''', - visitor_input_containers_decl=gen_visitor_input_containers_decl(args), + visitor_input_containers_decl=gen_visitor_input_containers_decl(args, "QOBJECT(args)"), visitor_input_vars_decl=gen_visitor_input_vars_decl(args), - visitor_input_block=gen_visitor_input_block(args, "QOBJECT(args)")) + visitor_input_block=gen_visitor_input_block(args)) else: ret += mcgen(''' + (void)args; ''') ret += mcgen(''' - if (error_is_set(errp)) { - goto out; - } %(sync_call)s ''', sync_call=gen_sync_call(name, args, ret_type, indent=4)) - ret += mcgen(''' + if re.search('^ *goto out\\;', ret, re.MULTILINE): + ret += mcgen(''' out: ''') + if not middle_mode: + ret += mcgen(''' + error_propagate(errp, local_err); +''') ret += mcgen(''' %(visitor_input_block_cleanup)s ''', - visitor_input_block_cleanup=gen_visitor_input_block(args, None, + visitor_input_block_cleanup=gen_visitor_input_block(args, dealloc=True)) if middle_mode: diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py index c6579beed5..06a79f1631 100644 --- a/scripts/qapi-visit.py +++ b/scripts/qapi-visit.py @@ -2,21 +2,47 @@ # QAPI visitor generator # # Copyright IBM, Corp. 2011 +# Copyright (C) 2014 Red Hat, Inc. # # Authors: # Anthony Liguori <aliguori@us.ibm.com> # Michael Roth <mdroth@linux.vnet.ibm.com> +# Markus Armbruster <armbru@redhat.com> # # This work is licensed under the terms of the GNU GPL, version 2. # See the COPYING file in the top-level directory. from ordereddict import OrderedDict from qapi import * +import re import sys import os import getopt import errno +implicit_structs = [] + +def generate_visit_implicit_struct(type): + global implicit_structs + if type in implicit_structs: + return '' + implicit_structs.append(type) + return mcgen(''' + +static void visit_type_implicit_%(c_type)s(Visitor *m, %(c_type)s **obj, Error **errp) +{ + Error *err = NULL; + + visit_start_implicit_struct(m, (void **)obj, sizeof(%(c_type)s), &err); + if (!err) { + visit_type_%(c_type)s_fields(m, obj, errp); + visit_end_implicit_struct(m, &err); + } + error_propagate(errp, err); +} +''', + c_type=type_name(type)) + def generate_visit_struct_fields(name, field_prefix, fn_prefix, members, base = None): substructs = [] ret = '' @@ -35,6 +61,19 @@ def generate_visit_struct_fields(name, field_prefix, fn_prefix, members, base = nested_field_prefix = "%s%s." % (field_prefix, argname) ret += generate_visit_struct_fields(name, nested_field_prefix, nested_fn_prefix, argentry) + ret += mcgen(''' + +static void visit_type_%(full_name)s_field_%(c_name)s(Visitor *m, %(name)s **obj, Error **errp) +{ +''', + name=name, full_name=full_name, c_name=c_var(argname)) + ret += generate_visit_struct_body(full_name, argname, argentry) + ret += mcgen(''' +} +''') + + if base: + ret += generate_visit_implicit_struct(base) ret += mcgen(''' @@ -47,12 +86,9 @@ static void visit_type_%(full_name)s_fields(Visitor *m, %(name)s ** obj, Error * if base: ret += mcgen(''' -visit_start_implicit_struct(m, (void**) &(*obj)->%(c_name)s, sizeof(%(type)s), &err); -if (!err) { - visit_type_%(type)s_fields(m, &(*obj)->%(c_prefix)s%(c_name)s, &err); - error_propagate(errp, err); - err = NULL; - visit_end_implicit_struct(m, &err); +visit_type_implicit_%(type)s(m, &(*obj)->%(c_prefix)s%(c_name)s, &err); +if (err) { + goto out; } ''', c_prefix=c_var(field_prefix), @@ -61,15 +97,18 @@ if (!err) { for argname, argentry, optional, structured in parse_args(members): if optional: ret += mcgen(''' -visit_start_optional(m, &(*obj)->%(c_prefix)shas_%(c_name)s, "%(name)s", &err); -if ((*obj)->%(prefix)shas_%(c_name)s) { +visit_optional(m, &(*obj)->%(c_prefix)shas_%(c_name)s, "%(name)s", &err); +if (!err && (*obj)->%(prefix)shas_%(c_name)s) { ''', c_prefix=c_var(field_prefix), prefix=field_prefix, c_name=c_var(argname), name=argname) push_indent() if structured: - ret += generate_visit_struct_body(full_name, argname, argentry) + ret += mcgen(''' +visit_type_%(full_name)s_field_%(c_name)s(m, obj, &err); +''', + full_name=full_name, c_name=c_var(argname)) else: ret += mcgen(''' visit_type_%(type)s(m, &(*obj)->%(c_prefix)s%(c_name)s, "%(name)s", &err); @@ -82,12 +121,20 @@ visit_type_%(type)s(m, &(*obj)->%(c_prefix)s%(c_name)s, "%(name)s", &err); pop_indent() ret += mcgen(''' } -visit_end_optional(m, &err); +''') + ret += mcgen(''' +if (err) { + goto out; +} ''') pop_indent() - ret += mcgen(''' + if re.search('^ *goto out\\;', ret, re.MULTILINE): + ret += mcgen(''' +out: +''') + ret += mcgen(''' error_propagate(errp, err); } ''') @@ -96,9 +143,9 @@ visit_end_optional(m, &err); def generate_visit_struct_body(field_prefix, name, members): ret = mcgen(''' -if (!error_is_set(errp)) { + Error *err = NULL; + ''') - push_indent() if not field_prefix: full_name = name @@ -107,36 +154,26 @@ if (!error_is_set(errp)) { if len(field_prefix): ret += mcgen(''' -Error **errp = &err; /* from outer scope */ -Error *err = NULL; -visit_start_struct(m, NULL, "", "%(name)s", 0, &err); + visit_start_struct(m, NULL, "", "%(name)s", 0, &err); ''', name=name) else: ret += mcgen(''' -Error *err = NULL; -visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err); + visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err); ''', name=name) ret += mcgen(''' -if (!err) { - if (*obj) { - visit_type_%(name)s_fields(m, obj, &err); - error_propagate(errp, err); - err = NULL; + if (!err) { + if (*obj) { + visit_type_%(name)s_fields(m, obj, errp); + } + visit_end_struct(m, &err); } + error_propagate(errp, err); ''', name=full_name) - pop_indent() - ret += mcgen(''' - /* Always call end_struct if start_struct succeeded. */ - visit_end_struct(m, &err); - } - error_propagate(errp, err); -} -''') return ret def generate_visit_struct(expr): @@ -154,9 +191,7 @@ void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error ** ''', name=name) - push_indent() ret += generate_visit_struct_body("", name, members) - pop_indent() ret += mcgen(''' } @@ -168,24 +203,26 @@ def generate_visit_list(name, members): void visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char *name, Error **errp) { - GenericList *i, **prev = (GenericList **)obj; Error *err = NULL; + GenericList *i, **prev; - if (!error_is_set(errp)) { - visit_start_list(m, name, &err); - if (!err) { - for (; (i = visit_next_list(m, prev, &err)) != NULL; prev = &i) { - %(name)sList *native_i = (%(name)sList *)i; - visit_type_%(name)s(m, &native_i->value, NULL, &err); - } - error_propagate(errp, err); - err = NULL; - - /* Always call end_list if start_list succeeded. */ - visit_end_list(m, &err); - } - error_propagate(errp, err); + visit_start_list(m, name, &err); + if (err) { + goto out; } + + for (prev = (GenericList **)obj; + !err && (i = visit_next_list(m, prev, &err)) != NULL; + prev = &i) { + %(name)sList *native_i = (%(name)sList *)i; + visit_type_%(name)s(m, &native_i->value, NULL, &err); + } + + error_propagate(errp, err); + err = NULL; + visit_end_list(m, &err); +out: + error_propagate(errp, err); } ''', name=name) @@ -207,10 +244,15 @@ void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error ** { Error *err = NULL; - if (!error_is_set(errp)) { - visit_start_implicit_struct(m, (void**) obj, sizeof(%(name)s), &err); - visit_get_next_type(m, (int*) &(*obj)->kind, %(name)s_qtypes, name, &err); - switch ((*obj)->kind) { + visit_start_implicit_struct(m, (void**) obj, sizeof(%(name)s), &err); + if (err) { + goto out; + } + visit_get_next_type(m, (int*) &(*obj)->kind, %(name)s_qtypes, name, &err); + if (err) { + goto out_end; + } + switch ((*obj)->kind) { ''', name=name) @@ -225,22 +267,24 @@ void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error ** enum_full_value = generate_enum_full_value(disc_type, key) ret += mcgen(''' - case %(enum_full_value)s: - visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, name, &err); - break; + case %(enum_full_value)s: + visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, name, &err); + break; ''', enum_full_value = enum_full_value, c_type = type_name(members[key]), c_name = c_fun(key)) ret += mcgen(''' - default: - abort(); - } - error_propagate(errp, err); - err = NULL; - visit_end_implicit_struct(m, &err); + default: + abort(); } +out_end: + error_propagate(errp, err); + err = NULL; + visit_end_implicit_struct(m, &err); +out: + error_propagate(errp, err); } ''') @@ -277,40 +321,43 @@ def generate_visit_union(expr): del base_fields[discriminator] ret += generate_visit_struct_fields(name, "", "", base_fields) + if discriminator: + for key in members: + ret += generate_visit_implicit_struct(members[key]) + ret += mcgen(''' void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp) { Error *err = NULL; - if (!error_is_set(errp)) { - visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err); - if (!err) { - if (*obj) { + visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err); + if (err) { + goto out; + } + if (*obj) { ''', name=name) - - push_indent() - push_indent() - push_indent() - if base: ret += mcgen(''' - visit_type_%(name)s_fields(m, obj, &err); + visit_type_%(name)s_fields(m, obj, &err); + if (err) { + goto out_obj; + } ''', name=name) - pop_indent() - if not discriminator: disc_key = "type" else: disc_key = discriminator ret += mcgen(''' visit_type_%(disc_type)s(m, &(*obj)->kind, "%(disc_key)s", &err); - if (!err) { - switch ((*obj)->kind) { + if (err) { + goto out_obj; + } + switch ((*obj)->kind) { ''', disc_type = disc_type, disc_key = disc_key) @@ -319,47 +366,32 @@ void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error ** if not discriminator: fmt = 'visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, "data", &err);' else: - fmt = '''visit_start_implicit_struct(m, (void**) &(*obj)->%(c_name)s, sizeof(%(c_type)s), &err); - if (!err) { - visit_type_%(c_type)s_fields(m, &(*obj)->%(c_name)s, &err); - error_propagate(errp, err); - err = NULL; - visit_end_implicit_struct(m, &err); - }''' + fmt = 'visit_type_implicit_%(c_type)s(m, &(*obj)->%(c_name)s, &err);' enum_full_value = generate_enum_full_value(disc_type, key) ret += mcgen(''' - case %(enum_full_value)s: - ''' + fmt + ''' - break; + case %(enum_full_value)s: + ''' + fmt + ''' + break; ''', enum_full_value = enum_full_value, c_type=type_name(members[key]), c_name=c_fun(key)) ret += mcgen(''' - default: - abort(); - } + default: + abort(); } +out_obj: error_propagate(errp, err); err = NULL; } -''') - pop_indent() - ret += mcgen(''' - /* Always call end_struct if start_struct succeeded. */ - visit_end_struct(m, &err); - } + visit_end_struct(m, &err); +out: error_propagate(errp, err); } ''') - pop_indent(); - ret += mcgen(''' -} -''') - return ret def generate_declaration(name, members, genlist=True, builtin_type=False): @@ -476,7 +508,7 @@ fdecl.write(mcgen(''' /* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */ /* - * schema-defined QAPI visitor function + * schema-defined QAPI visitor functions * * Copyright IBM, Corp. 2011 * diff --git a/scripts/qapi.py b/scripts/qapi.py index ec806aabeb..86e96089af 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -73,13 +73,18 @@ class QAPIExprError(Exception): class QAPISchema: - def __init__(self, fp, input_relname=None, include_hist=[], parent_info=None): + def __init__(self, fp, input_relname=None, include_hist=[], + previously_included=[], parent_info=None): + """ include_hist is a stack used to detect inclusion cycles + previously_included is a global state used to avoid multiple + inclusions of the same file""" input_fname = os.path.abspath(fp.name) if input_relname is None: input_relname = fp.name self.input_dir = os.path.dirname(input_fname) self.input_file = input_relname self.include_hist = include_hist + [(input_relname, input_fname)] + previously_included.append(input_fname) self.parent_info = parent_info self.src = fp.read() if self.src == '' or self.src[-1] != '\n': @@ -106,13 +111,16 @@ class QAPISchema: for elem in self.include_hist): raise QAPIExprError(expr_info, "Inclusion loop for %s" % include) + # skip multiple include of the same file + if include_path in previously_included: + continue try: fobj = open(include_path, 'r') - except IOError as e: + except IOError, e: raise QAPIExprError(expr_info, '%s: %s' % (e.strerror, include)) - exprs_include = QAPISchema(fobj, include, - self.include_hist, expr_info) + exprs_include = QAPISchema(fobj, include, self.include_hist, + previously_included, expr_info) self.exprs.extend(exprs_include.exprs) else: expr_elem = {'expr': expr, |