From patchwork Fri Mar 11 23:05:32 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Anthony Liguori X-Patchwork-Id: 86473 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [199.232.76.165]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id AD40CB6F9D for ; Sat, 12 Mar 2011 10:18:57 +1100 (EST) Received: from localhost ([127.0.0.1]:57299 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1PyBbG-0002A0-K6 for incoming@patchwork.ozlabs.org; Fri, 11 Mar 2011 18:18:26 -0500 Received: from [140.186.70.92] (port=54666 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1PyBPJ-0004Bi-LD for qemu-devel@nongnu.org; Fri, 11 Mar 2011 18:06:09 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1PyBPE-0006wZ-9W for qemu-devel@nongnu.org; Fri, 11 Mar 2011 18:06:05 -0500 Received: from e3.ny.us.ibm.com ([32.97.182.143]:51534) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1PyBPE-0006wO-3E for qemu-devel@nongnu.org; Fri, 11 Mar 2011 18:06:00 -0500 Received: from d01dlp01.pok.ibm.com (d01dlp01.pok.ibm.com [9.56.224.56]) by e3.ny.us.ibm.com (8.14.4/8.13.1) with ESMTP id p2BMjibI010361 for ; Fri, 11 Mar 2011 17:45:44 -0500 Received: from d01relay06.pok.ibm.com (d01relay06.pok.ibm.com [9.56.227.116]) by d01dlp01.pok.ibm.com (Postfix) with ESMTP id 0546338C8039 for ; Fri, 11 Mar 2011 18:05:57 -0500 (EST) Received: from d01av04.pok.ibm.com (d01av04.pok.ibm.com [9.56.224.64]) by d01relay06.pok.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id p2BN5p402334880 for ; Fri, 11 Mar 2011 18:05:51 -0500 Received: from d01av04.pok.ibm.com (loopback [127.0.0.1]) by d01av04.pok.ibm.com (8.14.4/8.13.1/NCO v10.0 AVout) with ESMTP id p2BN5pnN027159 for ; Fri, 11 Mar 2011 18:05:51 -0500 Received: from localhost.localdomain (sig-9-65-217-31.mts.ibm.com [9.65.217.31]) by d01av04.pok.ibm.com (8.14.4/8.13.1/NCO v10.0 AVin) with ESMTP id p2BN5lGn026958; Fri, 11 Mar 2011 18:05:50 -0500 From: Anthony Liguori To: qemu-devel@nongnu.org Date: Fri, 11 Mar 2011 17:05:32 -0600 Message-Id: <1299884745-521-3-git-send-email-aliguori@us.ibm.com> X-Mailer: git-send-email 1.7.0.4 In-Reply-To: <1299884745-521-1-git-send-email-aliguori@us.ibm.com> References: <1299884745-521-1-git-send-email-aliguori@us.ibm.com> X-Content-Scanned: Fidelis XPS MAILER X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6, seldom 2.4 (older, 4) X-Received-From: 32.97.182.143 Cc: Adam Litke , Anthony Liguori , Luiz Capitulino , Avi Kivity , Markus Armbruster Subject: [Qemu-devel] [PATCH 02/15] qapi: add code generator for type marshallers X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org This code will marshal a QMP type from native representation to a QObject and vice versa. Marshaling from a native representation to a QObject can never generate an Error although the opposite direction may. Signed-off-by: Anthony Liguori --- v1 -> v2 - update code generator to use multiline strings - support proxy commands - support async commands diff --git a/Makefile b/Makefile index 6b9fd69..8f3a4d3 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ GENERATED_HEADERS = config-host.h trace.h qemu-options.def ifeq ($(TRACE_BACKEND),dtrace) GENERATED_HEADERS += trace-dtrace.h endif -GENERATED_HEADERS += qmp-types.h +GENERATED_HEADERS += qmp-types.h qmp-marshal-types.h ifneq ($(wildcard config-host.mak),) # Put the all: rule here so that config-host.mak can contain dependencies. @@ -153,7 +153,14 @@ qmp-types.c: $(SRC_PATH)/qmp-schema.json $(SRC_PATH)/qmp-gen.py qmp-types.h: $(SRC_PATH)/qmp-schema.json $(SRC_PATH)/qmp-gen.py $(call quiet-command,python $(SRC_PATH)/qmp-gen.py --types-header < $< > $@, " GEN $@") +qmp-marshal-types.c: $(SRC_PATH)/qmp-schema.json $(SRC_PATH)/qmp-gen.py + $(call quiet-command,python $(SRC_PATH)/qmp-gen.py --marshal-body < $< > $@, " GEN $@") + +qmp-marshal-types.h: $(SRC_PATH)/qmp-schema.json $(SRC_PATH)/qmp-gen.py + $(call quiet-command,python $(SRC_PATH)/qmp-gen.py --marshal-header < $< > $@, " GEN $@") + qmp-types.o: qmp-types.c qmp-types.h +qmp-marshal-types.o: qmp-marshal-types.c qmp-marshal-types.h qmp-types.h version.o: $(SRC_PATH)/version.rc config-host.mak $(call quiet-command,$(WINDRES) -I. -o $@ $<," RC $(TARGET_DIR)$@") diff --git a/Makefile.objs b/Makefile.objs index 710d99f..f51eab3 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -102,6 +102,7 @@ common-obj-y += qdev.o qdev-properties.o common-obj-y += block-migration.o common-obj-y += pflib.o common-obj-y += bitmap.o bitops.o +common-obj-y += qmp-marshal-types.o qmp-marshal-types-core.o common-obj-$(CONFIG_BRLAPI) += baum.o common-obj-$(CONFIG_POSIX) += migration-exec.o migration-unix.o migration-fd.o diff --git a/qmp-gen.py b/qmp-gen.py index cded2f6..02084d9 100644 --- a/qmp-gen.py +++ b/qmp-gen.py @@ -360,6 +360,205 @@ const char *qmp_type_%(dcc_name)s_to_str(%(name)s value, Error **errp) name=name) return ret +def gen_type_marshal_declaration(name, typeinfo): + if is_dict(typeinfo): + return mcgen(''' + +QObject *qmp_marshal_type_%(name)s(%(type)s src); +%(type)s qmp_unmarshal_type_%(name)s(QObject *src, Error **errp); +''', + name=name, type=qmp_type_to_c(name)) + + return '' + +def gen_metatype_def(typeinfo, name, lhs, sep='->', level=0): + new_lhs = 'qmp__member%d' % level + + ret = '' + + if type(typeinfo) == str: + ret += cgen(' %(lhs)s = %(marshal)s(%(name)s);', + lhs=lhs, name=name, + marshal=qmp_type_to_qobj(typeinfo)) + elif is_dict(typeinfo): + ret += mcgen(''' + { + QDict *qmp__dict = qdict_new(); + QObject *%(new_lhs)s; +''', + new_lhs=new_lhs) + for argname, argtype, optional in parse_args(typeinfo): + ret += cgen('') + if optional: + ret += mcgen(''' + if (%(name)s%(sep)shas_%(c_name)s) { +''', + name=name, sep=sep, + c_name=c_var(argname)) + push_indent() + push_indent() + ret += gen_metatype_def(argtype, '%s%s%s' % (name, sep, c_var(argname)), new_lhs, '.', level + 1) + pop_indent() + ret += mcgen(''' + qdict_put_obj(qmp__dict, "%(name)s", %(new_lhs)s); +''', + name=argname, new_lhs=new_lhs) + if optional: + pop_indent() + ret += mcgen(''' + } +''') + ret += mcgen(''' + %(lhs)s = QOBJECT(qmp__dict); + } +''', + lhs=lhs) + elif type(typeinfo) == list: + ret += mcgen(''' + { + QList *qmp__list = qlist_new(); + %(type)s %(new_lhs)s_i; + + for (%(new_lhs)s_i = %(name)s; %(new_lhs)s_i != NULL; %(new_lhs)s_i = %(new_lhs)s_i->next) { + QObject *qmp__member = %(marshal)s(%(new_lhs)s_i); + qlist_append_obj(qmp__list, qmp__member); + } + %(lhs)s = QOBJECT(qmp__list); + } +''', + type=qmp_type_to_c(typeinfo[0], True), + new_lhs=new_lhs, name=name, lhs=lhs, + marshal=qmp_type_to_qobj(typeinfo[0])) + + return ret + +def gen_metatype_undef(typeinfo, name, lhs, sep='->', level=0): + ret = '' + if type(typeinfo) == str: + ret += mcgen(''' + %(lhs)s = %(unmarshal)s(%(c_name)s, &qmp__err); + if (qmp__err) { + goto qmp__err_out; + } +''', + lhs=lhs, c_name=c_var(name), + unmarshal=qmp_type_from_qobj(typeinfo)) + elif is_dict(typeinfo): + objname = 'qmp__object%d' % level + ret += mcgen(''' + { + QDict *qmp__dict = qobject_to_qdict(%(c_name)s); + QObject *%(objname)s; + +''', + c_name=c_var(name), objname=objname) + for argname, argtype, optional in parse_args(typeinfo): + if optional: + ret += mcgen(''' + if (qdict_haskey(qmp__dict, "%(name)s")) { +''', + name=argname) + push_indent() + ret += mcgen(''' + %(objname)s = qdict_get(qmp__dict, "%(name)s"); +''', + name=argname, objname=objname) + push_indent() + ret += gen_metatype_undef(argtype, objname, '%s%s%s' % (lhs, sep, c_var(argname)), '.', level + 1) + pop_indent() + if optional: + pop_indent() + ret += mcgen(''' + %(lhs)s%(sep)shas_%(c_name)s = true; + } else { + %(lhs)s%(sep)shas_%(c_name)s = false; + } +''', + lhs=lhs, sep=sep, c_name=c_var(argname)) + + ret += mcgen(''' + } +''') + + elif type(typeinfo) == list: + objname = 'qmp__object%d' % level + ret += mcgen(''' + { + QList *qmp__list = qobject_to_qlist(%(c_name)s); + QListEntry *%(objname)s; + QLIST_FOREACH_ENTRY(qmp__list, %(objname)s) { + %(type)s qmp__node = %(unmarshal)s(%(objname)s->value, &qmp__err); + if (qmp__err) { + goto qmp__err_out; + } + qmp__node->next = %(lhs)s; + %(lhs)s = qmp__node; + } + } +''', + c_name=c_var(name), objname=objname, lhs=lhs, + type=qmp_type_to_c(typeinfo[0], True), + unmarshal=qmp_type_from_qobj(typeinfo[0])) + + return ret + +def gen_type_marshal_definition(name, typeinfo): + ret = mcgen(''' + +QObject *qmp_marshal_type_%(name)s(%(type)s src) +{ + QObject *qmp__retval; + +%(marshal)s + + return qmp__retval; +} + +%(type)s qmp_unmarshal_type_%(name)s(QObject *src, Error **errp) +{ + Error *qmp__err = NULL; + %(type)s qmp__retval = qmp_alloc_%(dcc_name)s(); + +%(unmarshal)s + + return qmp__retval; + +qmp__err_out: + error_propagate(errp, qmp__err); + %(free)s(qmp__retval); + return NULL; +} +''', + name=name, type=qmp_type_to_c(name), + marshal=gen_metatype_def(typeinfo, 'src', 'qmp__retval'), + dcc_name=de_camel_case(name), free=qmp_free_func(name), + unmarshal=gen_metatype_undef(typeinfo, 'src', 'qmp__retval')) + + return ret + +def gen_enum_marshal_declaration(name, entries): + return mcgen(''' + +QObject *qmp_marshal_type_%(name)s(%(name)s value); +%(name)s qmp_unmarshal_type_%(name)s(QObject *obj, Error **errp); +''', + name=name) + +def gen_enum_marshal_definition(name, entries): + return mcgen(''' + +QObject *qmp_marshal_type_%(name)s(%(name)s value) +{ + return QOBJECT(qint_from_int(value)); +} + +%(name)s qmp_unmarshal_type_%(name)s(QObject *obj, Error **errp) +{ + return (%(name)s)qint_get_int(qobject_to_qint(obj)); +} +''', + name=name) + def tokenize(data): while len(data): if data[0] in ['{', '}', ':', ',', '[', ']']: @@ -436,6 +635,18 @@ def generate(kind): #include "qmp-types.h" #include "qmp-marshal-types.h" ''') + elif kind == 'marshal-header': + ret += mcgen(''' +#ifndef QMP_MARSHAL_TYPES_H +#define QMP_MARSHAL_TYPES_H + +#include "qmp-marshal-types-core.h" +''') + elif kind == 'marshal-body': + ret += mcgen(''' +#include "qmp-marshal-types.h" +#include "qerror.h" +''') exprs = [] expr = '' @@ -466,6 +677,10 @@ def generate(kind): ret += gen_type_definition(name, data) elif kind == 'types-header': ret += gen_type_declaration(name, data) + elif kind == 'marshal-body': + ret += gen_type_marshal_definition(name, data) + elif kind == 'marshal-header': + ret += gen_type_marshal_declaration(name, data) elif s.has_key('enum'): name = s['enum'] data = s['data'] @@ -475,6 +690,10 @@ def generate(kind): ret += gen_enum_declaration(name, data) elif kind == 'types-body': ret += gen_enum_definition(name, data) + elif kind == 'marshal-header': + ret += gen_enum_marshal_declaration(name, data) + elif kind == 'marshal-body': + ret += gen_enum_marshal_definition(name, data) elif s.has_key('event'): name = s['event'] data = {} diff --git a/qmp-marshal-types-core.c b/qmp-marshal-types-core.c new file mode 100644 index 0000000..6a55733 --- /dev/null +++ b/qmp-marshal-types-core.c @@ -0,0 +1,71 @@ +/* + * QAPI + * + * Copyright IBM, Corp. 2011 + * + * Authors: + * Anthony Liguori + * + * This work is licensed under the terms of the GNU LGPL, version 2. See + * the COPYING.LIB file in the top-level directory. + */ +#include "qmp-marshal-types-core.h" +#include "qerror.h" + +QObject *qmp_marshal_type_int(int64_t value) +{ + return QOBJECT(qint_from_int(value)); +} + +QObject *qmp_marshal_type_str(const char *value) +{ + return QOBJECT(qstring_from_str(value)); +} + +QObject *qmp_marshal_type_bool(bool value) +{ + return QOBJECT(qbool_from_int(value)); +} + +QObject *qmp_marshal_type_number(double value) +{ + return QOBJECT(qfloat_from_double(value)); +} + +int64_t qmp_unmarshal_type_int(QObject *value, Error **errp) +{ + if (qobject_type(value) != QTYPE_QINT) { + error_set(errp, QERR_INVALID_PARAMETER_TYPE, "", "int"); + return 0; + } + return qint_get_int(qobject_to_qint(value)); +} + +char *qmp_unmarshal_type_str(QObject *value, Error **errp) +{ + if (qobject_type(value) != QTYPE_QSTRING) { + error_set(errp, QERR_INVALID_PARAMETER_TYPE, "", "string"); + return 0; + } + return qemu_strdup(qstring_get_str(qobject_to_qstring(value))); +} + +bool qmp_unmarshal_type_bool(QObject *value, Error **errp) +{ + if (qobject_type(value) != QTYPE_QBOOL) { + error_set(errp, QERR_INVALID_PARAMETER_TYPE, "", "bool"); + return 0; + } + return qbool_get_int(qobject_to_qbool(value)); +} + +double qmp_unmarshal_type_number(QObject *value, Error **errp) +{ + if (qobject_type(value) != QTYPE_QFLOAT) { + error_set(errp, QERR_INVALID_PARAMETER_TYPE, "", "float"); + return 0; + } + return qfloat_get_double(qobject_to_qfloat(value)); +} + + diff --git a/qmp-marshal-types-core.h b/qmp-marshal-types-core.h new file mode 100644 index 0000000..38fe696 --- /dev/null +++ b/qmp-marshal-types-core.h @@ -0,0 +1,31 @@ +/* + * QAPI + * + * Copyright IBM, Corp. 2011 + * + * Authors: + * Anthony Liguori + * + * This work is licensed under the terms of the GNU LGPL, version 2. See + * the COPYING.LIB file in the top-level directory. + */ +#ifndef QMP_MARSHAL_TYPES_CORE_H +#define QMP_MARSHAL_TYPES_CORE_H + +#include "qemu-common.h" +#include "qemu-objects.h" +#include "qerror.h" +#include "error.h" +#include "qmp-types.h" + +QObject *qmp_marshal_type_int(int64_t value); +QObject *qmp_marshal_type_str(const char *value); +QObject *qmp_marshal_type_bool(bool value); +QObject *qmp_marshal_type_number(double value); + +int64_t qmp_unmarshal_type_int(QObject *value, Error **errp); +char *qmp_unmarshal_type_str(QObject *value, Error **errp); +bool qmp_unmarshal_type_bool(QObject *value, Error **errp); +double qmp_unmarshal_type_number(QObject *value, Error **errp); + +#endif