* [Qemu-devel] [PATCH v3 01/21] Add hard build dependency on glib
2011-06-14 2:31 [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v3 Michael Roth
@ 2011-06-14 2:31 ` Michael Roth
2011-06-14 2:31 ` [Qemu-devel] [PATCH v3 02/21] qlist: add qlist_first()/qlist_next() Michael Roth
` (19 subsequent siblings)
20 siblings, 0 replies; 37+ messages in thread
From: Michael Roth @ 2011-06-14 2:31 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, Jes.Sorensen, agl, mdroth, lcapitulino
From: Anthony Liguori <aliguori@us.ibm.com>
GLib is an extremely common library that has a portable thread implementation
along with tons of other goodies.
GLib and GObject have a fantastic amount of infrastructure we can leverage in
QEMU including an object oriented programming infrastructure.
Short term, it has a very nice thread pool implementation that we could leverage
in something like virtio-9p. It also has a test harness implementation that
this series will use.
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
Makefile | 2 ++
Makefile.objs | 2 ++
Makefile.target | 1 +
configure | 13 +++++++++++++
4 files changed, 18 insertions(+), 0 deletions(-)
diff --git a/Makefile b/Makefile
index 096480b..306cd9b 100644
--- a/Makefile
+++ b/Makefile
@@ -106,6 +106,8 @@ audio/audio.o audio/fmodaudio.o: QEMU_CFLAGS += $(FMOD_CFLAGS)
QEMU_CFLAGS+=$(CURL_CFLAGS)
+QEMU_CFLAGS+=$(GLIB_CFLAGS)
+
ui/cocoa.o: ui/cocoa.m
ui/sdl.o audio/sdlaudio.o ui/sdl_zoom.o baum.o: QEMU_CFLAGS += $(SDL_CFLAGS)
diff --git a/Makefile.objs b/Makefile.objs
index 52d8b23..a7807e8 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -368,3 +368,5 @@ vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
vl.o: QEMU_CFLAGS+=$(SDL_CFLAGS)
+vl.o: QEMU_CFLAGS+=$(GLIB_CFLAGS)
+
diff --git a/Makefile.target b/Makefile.target
index b1a0f6d..0d900e2 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -202,6 +202,7 @@ QEMU_CFLAGS += $(VNC_TLS_CFLAGS)
QEMU_CFLAGS += $(VNC_SASL_CFLAGS)
QEMU_CFLAGS += $(VNC_JPEG_CFLAGS)
QEMU_CFLAGS += $(VNC_PNG_CFLAGS)
+QEMU_CFLAGS += $(GLIB_CFLAGS)
# xen backend driver support
obj-i386-$(CONFIG_XEN) += xen_machine_pv.o xen_domainbuild.o
diff --git a/configure b/configure
index c931ae8..d3a3a96 100755
--- a/configure
+++ b/configure
@@ -1767,6 +1767,18 @@ EOF
fi
##########################################
+# glib support probe
+if $pkg_config --modversion gthread-2.0 gio-2.0 > /dev/null 2>&1 ; then
+ glib_cflags=`$pkg_config --cflags gthread-2.0 gio-2.0 2>/dev/null`
+ glib_libs=`$pkg_config --libs gthread-2.0 gio-2.0 2>/dev/null`
+ libs_softmmu="$glib_libs $libs_softmmu"
+ libs_tools="$glib_libs $libs_tools"
+else
+ echo "glib-2.0 required to compile QEMU"
+ exit 1
+fi
+
+##########################################
# kvm probe
if test "$kvm" != "no" ; then
cat > $TMPC <<EOF
@@ -2923,6 +2935,7 @@ if test "$bluez" = "yes" ; then
echo "CONFIG_BLUEZ=y" >> $config_host_mak
echo "BLUEZ_CFLAGS=$bluez_cflags" >> $config_host_mak
fi
+echo "GLIB_CFLAGS=$glib_cflags" >> $config_host_mak
if test "$xen" = "yes" ; then
echo "CONFIG_XEN=y" >> $config_host_mak
echo "CONFIG_XEN_CTRL_INTERFACE_VERSION=$xen_ctrl_version" >> $config_host_mak
--
1.7.0.4
^ permalink raw reply related [flat|nested] 37+ messages in thread
* [Qemu-devel] [PATCH v3 02/21] qlist: add qlist_first()/qlist_next()
2011-06-14 2:31 [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v3 Michael Roth
2011-06-14 2:31 ` [Qemu-devel] [PATCH v3 01/21] Add hard build dependency on glib Michael Roth
@ 2011-06-14 2:31 ` Michael Roth
2011-06-14 2:31 ` [Qemu-devel] [PATCH v3 03/21] qapi: add module init types for qapi Michael Roth
` (18 subsequent siblings)
20 siblings, 0 replies; 37+ messages in thread
From: Michael Roth @ 2011-06-14 2:31 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, Jes.Sorensen, agl, mdroth, lcapitulino
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
qlist.h | 11 +++++++++++
1 files changed, 11 insertions(+), 0 deletions(-)
diff --git a/qlist.h b/qlist.h
index dbe7b92..d426bd4 100644
--- a/qlist.h
+++ b/qlist.h
@@ -16,6 +16,7 @@
#include "qobject.h"
#include "qemu-queue.h"
#include "qemu-common.h"
+#include "qemu-queue.h"
typedef struct QListEntry {
QObject *value;
@@ -50,4 +51,14 @@ QObject *qlist_peek(QList *qlist);
int qlist_empty(const QList *qlist);
QList *qobject_to_qlist(const QObject *obj);
+static inline const QListEntry *qlist_first(const QList *qlist)
+{
+ return QTAILQ_FIRST(&qlist->head);
+}
+
+static inline const QListEntry *qlist_next(const QListEntry *entry)
+{
+ return QTAILQ_NEXT(entry, next);
+}
+
#endif /* QLIST_H */
--
1.7.0.4
^ permalink raw reply related [flat|nested] 37+ messages in thread
* [Qemu-devel] [PATCH v3 03/21] qapi: add module init types for qapi
2011-06-14 2:31 [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v3 Michael Roth
2011-06-14 2:31 ` [Qemu-devel] [PATCH v3 01/21] Add hard build dependency on glib Michael Roth
2011-06-14 2:31 ` [Qemu-devel] [PATCH v3 02/21] qlist: add qlist_first()/qlist_next() Michael Roth
@ 2011-06-14 2:31 ` Michael Roth
2011-06-14 2:31 ` [Qemu-devel] [PATCH v3 04/21] qapi: add QAPI visitor core Michael Roth
` (17 subsequent siblings)
20 siblings, 0 replies; 37+ messages in thread
From: Michael Roth @ 2011-06-14 2:31 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, Jes.Sorensen, agl, mdroth, lcapitulino
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
module.h | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/module.h b/module.h
index 9263f1c..ef66730 100644
--- a/module.h
+++ b/module.h
@@ -24,12 +24,14 @@ typedef enum {
MODULE_INIT_BLOCK,
MODULE_INIT_DEVICE,
MODULE_INIT_MACHINE,
+ MODULE_INIT_QAPI,
MODULE_INIT_MAX
} module_init_type;
#define block_init(function) module_init(function, MODULE_INIT_BLOCK)
#define device_init(function) module_init(function, MODULE_INIT_DEVICE)
#define machine_init(function) module_init(function, MODULE_INIT_MACHINE)
+#define qapi_init(function) module_init(function, MODULE_INIT_QAPI)
void register_module_init(void (*fn)(void), module_init_type type);
--
1.7.0.4
^ permalink raw reply related [flat|nested] 37+ messages in thread
* [Qemu-devel] [PATCH v3 04/21] qapi: add QAPI visitor core
2011-06-14 2:31 [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v3 Michael Roth
` (2 preceding siblings ...)
2011-06-14 2:31 ` [Qemu-devel] [PATCH v3 03/21] qapi: add module init types for qapi Michael Roth
@ 2011-06-14 2:31 ` Michael Roth
2011-06-15 14:33 ` Luiz Capitulino
2011-06-14 2:31 ` [Qemu-devel] [PATCH v3 05/21] qapi: add QMP input visitor Michael Roth
` (16 subsequent siblings)
20 siblings, 1 reply; 37+ messages in thread
From: Michael Roth @ 2011-06-14 2:31 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, Jes.Sorensen, agl, mdroth, lcapitulino
Base definitions/includes for Visiter interface used by generated
visiter/marshalling code.
Includes a GenericList type. Our lists require an embedded element.
Since these types are generated, if you want to use them in a different
type of data structure, there's no easy way to add another embedded
element. The solution is to have non-embedded lists and that what this is.
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
Makefile.objs | 6 +++
qapi/qapi-types-core.h | 21 ++++++++++
qapi/qapi-visit-core.c | 101 ++++++++++++++++++++++++++++++++++++++++++++++++
qapi/qapi-visit-core.h | 68 ++++++++++++++++++++++++++++++++
4 files changed, 196 insertions(+), 0 deletions(-)
create mode 100644 qapi/qapi-types-core.h
create mode 100644 qapi/qapi-visit-core.c
create mode 100644 qapi/qapi-visit-core.h
diff --git a/Makefile.objs b/Makefile.objs
index a7807e8..68d7b5a 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -364,6 +364,12 @@ endif
libcacard-y = cac.o event.o vcard.o vreader.o vcard_emul_nss.o vcard_emul_type.o card_7816.o
+######################################################################
+# qapi
+
+qapi-nested-y = qapi-visit-core.o
+qapi-obj-y = $(addprefix qapi/, $(qapi-nested-y))
+
vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
vl.o: QEMU_CFLAGS+=$(SDL_CFLAGS)
diff --git a/qapi/qapi-types-core.h b/qapi/qapi-types-core.h
new file mode 100644
index 0000000..de733ab
--- /dev/null
+++ b/qapi/qapi-types-core.h
@@ -0,0 +1,21 @@
+/*
+ * Core Definitions for QAPI-generated Types
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#ifndef QAPI_TYPES_CORE_H
+#define QAPI_TYPES_CORE_H
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "error.h"
+
+#endif
diff --git a/qapi/qapi-visit-core.c b/qapi/qapi-visit-core.c
new file mode 100644
index 0000000..948818e
--- /dev/null
+++ b/qapi/qapi-visit-core.c
@@ -0,0 +1,101 @@
+#include "qapi/qapi-visit-core.h"
+
+void visit_start_handle(Visitor *v, void **obj, const char *kind, const char *name, Error **errp)
+{
+ if (!error_is_set(errp) && v->start_handle) {
+ v->start_handle(v, obj, kind, name, errp);
+ }
+}
+
+void visit_end_handle(Visitor *v, Error **errp)
+{
+ if (!error_is_set(errp) && v->end_handle) {
+ v->end_handle(v, errp);
+ }
+}
+
+void visit_start_struct(Visitor *v, void **obj, const char *kind, const char *name, size_t size, Error **errp)
+{
+ if (!error_is_set(errp)) {
+ v->start_struct(v, obj, kind, name, size, errp);
+ }
+}
+
+void visit_end_struct(Visitor *v, Error **errp)
+{
+ if (!error_is_set(errp)) {
+ v->end_struct(v, errp);
+ }
+}
+
+void visit_start_list(Visitor *v, const char *name, Error **errp)
+{
+ if (!error_is_set(errp)) {
+ v->start_list(v, name, errp);
+ }
+}
+
+GenericList *visit_next_list(Visitor *v, GenericList **list, Error **errp)
+{
+ if (!error_is_set(errp)) {
+ return v->next_list(v, list, errp);
+ }
+
+ return 0;
+}
+
+void visit_end_list(Visitor *v, Error **errp)
+{
+ if (!error_is_set(errp)) {
+ v->end_list(v, errp);
+ }
+}
+
+void visit_start_optional(Visitor *v, bool *present, const char *name, Error **errp)
+{
+ if (!error_is_set(errp) && v->start_optional) {
+ v->start_optional(v, present, name, errp);
+ }
+}
+
+void visit_end_optional(Visitor *v, Error **errp)
+{
+ if (!error_is_set(errp) && v->end_optional) {
+ v->end_optional(v, errp);
+ }
+}
+
+void visit_type_enum(Visitor *v, int *obj, const char *kind, const char *name, Error **errp)
+{
+ if (!error_is_set(errp)) {
+ v->type_enum(v, obj, kind, name, errp);
+ }
+}
+
+void visit_type_int(Visitor *v, int64_t *obj, const char *name, Error **errp)
+{
+ if (!error_is_set(errp)) {
+ v->type_int(v, obj, name, errp);
+ }
+}
+
+void visit_type_bool(Visitor *v, bool *obj, const char *name, Error **errp)
+{
+ if (!error_is_set(errp)) {
+ v->type_bool(v, obj, name, errp);
+ }
+}
+
+void visit_type_str(Visitor *v, char **obj, const char *name, Error **errp)
+{
+ if (!error_is_set(errp)) {
+ v->type_str(v, obj, name, errp);
+ }
+}
+
+void visit_type_number(Visitor *v, double *obj, const char *name, Error **errp)
+{
+ if (!error_is_set(errp)) {
+ v->type_number(v, obj, name, errp);
+ }
+}
diff --git a/qapi/qapi-visit-core.h b/qapi/qapi-visit-core.h
new file mode 100644
index 0000000..8350a6d
--- /dev/null
+++ b/qapi/qapi-visit-core.h
@@ -0,0 +1,68 @@
+/*
+ * Core Definitions for QAPI Visitor Classes
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+#ifndef QAPI_VISITOR_CORE_H
+#define QAPI_VISITOR_CORE_H
+
+#include "qapi/qapi-types-core.h"
+#include "error.h"
+#include <stdlib.h>
+
+typedef struct GenericList
+{
+ void *value;
+ struct GenericList *next;
+} GenericList;
+
+typedef struct Visitor Visitor;
+
+struct Visitor
+{
+ /* Must be set */
+ void (*start_struct)(Visitor *v, void **obj, const char *kind, const char *name, size_t size, Error **errp);
+ void (*end_struct)(Visitor *v, Error **errp);
+
+ void (*start_list)(Visitor *v, const char *name, Error **errp);
+ GenericList *(*next_list)(Visitor *v, GenericList **list, Error **errp);
+ void (*end_list)(Visitor *v, Error **errp);
+
+ void (*type_enum)(Visitor *v, int *obj, const char *kind, const char *name, Error **errp);
+
+ void (*type_int)(Visitor *v, int64_t *obj, const char *name, Error **errp);
+ void (*type_bool)(Visitor *v, bool *obj, const char *name, Error **errp);
+ void (*type_str)(Visitor *v, char **obj, const char *name, Error **errp);
+ void (*type_number)(Visitor *v, double *obj, const char *name, Error **errp);
+
+ /* May be NULL */
+ void (*start_optional)(Visitor *v, bool *present, const char *name, Error **errp);
+ void (*end_optional)(Visitor *v, Error **errp);
+
+ void (*start_handle)(Visitor *v, void **obj, const char *kind, const char *name, Error **errp);
+ void (*end_handle)(Visitor *v, Error **errp);
+};
+
+void visit_start_handle(Visitor *v, void **obj, const char *kind, const char *name, Error **errp);
+void visit_end_handle(Visitor *v, Error **errp);
+void visit_start_struct(Visitor *v, void **obj, const char *kind, const char *name, size_t size, Error **errp);
+void visit_end_struct(Visitor *v, Error **errp);
+void visit_start_list(Visitor *v, const char *name, Error **errp);
+GenericList *visit_next_list(Visitor *v, GenericList **list, Error **errp);
+void visit_end_list(Visitor *v, Error **errp);
+void visit_start_optional(Visitor *v, bool *present, const char *name, Error **errp);
+void visit_end_optional(Visitor *v, Error **errp);
+void visit_type_enum(Visitor *v, int *obj, const char *kind, const char *name, Error **errp);
+void visit_type_int(Visitor *v, int64_t *obj, const char *name, Error **errp);
+void visit_type_bool(Visitor *v, bool *obj, const char *name, Error **errp);
+void visit_type_str(Visitor *v, char **obj, const char *name, Error **errp);
+void visit_type_number(Visitor *v, double *obj, const char *name, Error **errp);
+
+#endif
--
1.7.0.4
^ permalink raw reply related [flat|nested] 37+ messages in thread
* Re: [Qemu-devel] [PATCH v3 04/21] qapi: add QAPI visitor core
2011-06-14 2:31 ` [Qemu-devel] [PATCH v3 04/21] qapi: add QAPI visitor core Michael Roth
@ 2011-06-15 14:33 ` Luiz Capitulino
2011-06-15 14:54 ` Michael Roth
0 siblings, 1 reply; 37+ messages in thread
From: Luiz Capitulino @ 2011-06-15 14:33 UTC (permalink / raw)
To: Michael Roth; +Cc: aliguori, agl, qemu-devel, Jes.Sorensen
On Mon, 13 Jun 2011 21:31:09 -0500
Michael Roth <mdroth@linux.vnet.ibm.com> wrote:
> Base definitions/includes for Visiter interface used by generated
> visiter/marshalling code.
>
> Includes a GenericList type. Our lists require an embedded element.
> Since these types are generated, if you want to use them in a different
> type of data structure, there's no easy way to add another embedded
> element. The solution is to have non-embedded lists and that what this is.
>
> Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
> ---
> Makefile.objs | 6 +++
> qapi/qapi-types-core.h | 21 ++++++++++
> qapi/qapi-visit-core.c | 101 ++++++++++++++++++++++++++++++++++++++++++++++++
> qapi/qapi-visit-core.h | 68 ++++++++++++++++++++++++++++++++
> 4 files changed, 196 insertions(+), 0 deletions(-)
> create mode 100644 qapi/qapi-types-core.h
> create mode 100644 qapi/qapi-visit-core.c
> create mode 100644 qapi/qapi-visit-core.h
>
> diff --git a/Makefile.objs b/Makefile.objs
> index a7807e8..68d7b5a 100644
> --- a/Makefile.objs
> +++ b/Makefile.objs
> @@ -364,6 +364,12 @@ endif
>
> libcacard-y = cac.o event.o vcard.o vreader.o vcard_emul_nss.o vcard_emul_type.o card_7816.o
>
> +######################################################################
> +# qapi
> +
> +qapi-nested-y = qapi-visit-core.o
> +qapi-obj-y = $(addprefix qapi/, $(qapi-nested-y))
To build this I have to add qapi-obj-y to common-obj-y and add the
qapi directory to the DIR variable in configure (so that it builds
in a different directory).
I saw that you send the configure change in a different patch, but it
has to be done here.
> +
> vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
>
> vl.o: QEMU_CFLAGS+=$(SDL_CFLAGS)
> diff --git a/qapi/qapi-types-core.h b/qapi/qapi-types-core.h
> new file mode 100644
> index 0000000..de733ab
> --- /dev/null
> +++ b/qapi/qapi-types-core.h
> @@ -0,0 +1,21 @@
> +/*
> + * Core Definitions for QAPI-generated Types
> + *
> + * Copyright IBM, Corp. 2011
> + *
> + * Authors:
> + * Anthony Liguori <aliguori@us.ibm.com>
> + *
> + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
> + * See the COPYING.LIB file in the top-level directory.
> + *
> + */
> +
> +#ifndef QAPI_TYPES_CORE_H
> +#define QAPI_TYPES_CORE_H
> +
> +#include <stdbool.h>
> +#include <stdint.h>
> +#include "error.h"
> +
> +#endif
> diff --git a/qapi/qapi-visit-core.c b/qapi/qapi-visit-core.c
> new file mode 100644
> index 0000000..948818e
> --- /dev/null
> +++ b/qapi/qapi-visit-core.c
> @@ -0,0 +1,101 @@
> +#include "qapi/qapi-visit-core.h"
No license info.
> +
> +void visit_start_handle(Visitor *v, void **obj, const char *kind, const char *name, Error **errp)
> +{
> + if (!error_is_set(errp) && v->start_handle) {
> + v->start_handle(v, obj, kind, name, errp);
> + }
> +}
> +
> +void visit_end_handle(Visitor *v, Error **errp)
> +{
> + if (!error_is_set(errp) && v->end_handle) {
> + v->end_handle(v, errp);
> + }
> +}
> +
> +void visit_start_struct(Visitor *v, void **obj, const char *kind, const char *name, size_t size, Error **errp)
> +{
> + if (!error_is_set(errp)) {
> + v->start_struct(v, obj, kind, name, size, errp);
> + }
> +}
> +
> +void visit_end_struct(Visitor *v, Error **errp)
> +{
> + if (!error_is_set(errp)) {
> + v->end_struct(v, errp);
> + }
> +}
> +
> +void visit_start_list(Visitor *v, const char *name, Error **errp)
> +{
> + if (!error_is_set(errp)) {
> + v->start_list(v, name, errp);
> + }
> +}
> +
> +GenericList *visit_next_list(Visitor *v, GenericList **list, Error **errp)
> +{
> + if (!error_is_set(errp)) {
> + return v->next_list(v, list, errp);
> + }
> +
> + return 0;
> +}
> +
> +void visit_end_list(Visitor *v, Error **errp)
> +{
> + if (!error_is_set(errp)) {
> + v->end_list(v, errp);
> + }
> +}
> +
> +void visit_start_optional(Visitor *v, bool *present, const char *name, Error **errp)
> +{
> + if (!error_is_set(errp) && v->start_optional) {
> + v->start_optional(v, present, name, errp);
> + }
> +}
> +
> +void visit_end_optional(Visitor *v, Error **errp)
> +{
> + if (!error_is_set(errp) && v->end_optional) {
> + v->end_optional(v, errp);
> + }
> +}
> +
> +void visit_type_enum(Visitor *v, int *obj, const char *kind, const char *name, Error **errp)
> +{
> + if (!error_is_set(errp)) {
> + v->type_enum(v, obj, kind, name, errp);
> + }
> +}
> +
> +void visit_type_int(Visitor *v, int64_t *obj, const char *name, Error **errp)
> +{
> + if (!error_is_set(errp)) {
> + v->type_int(v, obj, name, errp);
> + }
> +}
> +
> +void visit_type_bool(Visitor *v, bool *obj, const char *name, Error **errp)
> +{
> + if (!error_is_set(errp)) {
> + v->type_bool(v, obj, name, errp);
> + }
> +}
> +
> +void visit_type_str(Visitor *v, char **obj, const char *name, Error **errp)
> +{
> + if (!error_is_set(errp)) {
> + v->type_str(v, obj, name, errp);
> + }
> +}
> +
> +void visit_type_number(Visitor *v, double *obj, const char *name, Error **errp)
> +{
> + if (!error_is_set(errp)) {
> + v->type_number(v, obj, name, errp);
> + }
> +}
> diff --git a/qapi/qapi-visit-core.h b/qapi/qapi-visit-core.h
> new file mode 100644
> index 0000000..8350a6d
> --- /dev/null
> +++ b/qapi/qapi-visit-core.h
> @@ -0,0 +1,68 @@
> +/*
> + * Core Definitions for QAPI Visitor Classes
> + *
> + * Copyright IBM, Corp. 2011
> + *
> + * Authors:
> + * Anthony Liguori <aliguori@us.ibm.com>
> + *
> + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
> + * See the COPYING.LIB file in the top-level directory.
> + *
> + */
> +#ifndef QAPI_VISITOR_CORE_H
> +#define QAPI_VISITOR_CORE_H
> +
> +#include "qapi/qapi-types-core.h"
> +#include "error.h"
> +#include <stdlib.h>
> +
> +typedef struct GenericList
> +{
> + void *value;
> + struct GenericList *next;
> +} GenericList;
> +
> +typedef struct Visitor Visitor;
> +
> +struct Visitor
> +{
> + /* Must be set */
> + void (*start_struct)(Visitor *v, void **obj, const char *kind, const char *name, size_t size, Error **errp);
> + void (*end_struct)(Visitor *v, Error **errp);
> +
> + void (*start_list)(Visitor *v, const char *name, Error **errp);
> + GenericList *(*next_list)(Visitor *v, GenericList **list, Error **errp);
> + void (*end_list)(Visitor *v, Error **errp);
> +
> + void (*type_enum)(Visitor *v, int *obj, const char *kind, const char *name, Error **errp);
> +
> + void (*type_int)(Visitor *v, int64_t *obj, const char *name, Error **errp);
> + void (*type_bool)(Visitor *v, bool *obj, const char *name, Error **errp);
> + void (*type_str)(Visitor *v, char **obj, const char *name, Error **errp);
> + void (*type_number)(Visitor *v, double *obj, const char *name, Error **errp);
> +
> + /* May be NULL */
> + void (*start_optional)(Visitor *v, bool *present, const char *name, Error **errp);
> + void (*end_optional)(Visitor *v, Error **errp);
> +
> + void (*start_handle)(Visitor *v, void **obj, const char *kind, const char *name, Error **errp);
> + void (*end_handle)(Visitor *v, Error **errp);
> +};
> +
> +void visit_start_handle(Visitor *v, void **obj, const char *kind, const char *name, Error **errp);
> +void visit_end_handle(Visitor *v, Error **errp);
> +void visit_start_struct(Visitor *v, void **obj, const char *kind, const char *name, size_t size, Error **errp);
> +void visit_end_struct(Visitor *v, Error **errp);
> +void visit_start_list(Visitor *v, const char *name, Error **errp);
> +GenericList *visit_next_list(Visitor *v, GenericList **list, Error **errp);
> +void visit_end_list(Visitor *v, Error **errp);
> +void visit_start_optional(Visitor *v, bool *present, const char *name, Error **errp);
> +void visit_end_optional(Visitor *v, Error **errp);
> +void visit_type_enum(Visitor *v, int *obj, const char *kind, const char *name, Error **errp);
> +void visit_type_int(Visitor *v, int64_t *obj, const char *name, Error **errp);
> +void visit_type_bool(Visitor *v, bool *obj, const char *name, Error **errp);
> +void visit_type_str(Visitor *v, char **obj, const char *name, Error **errp);
> +void visit_type_number(Visitor *v, double *obj, const char *name, Error **errp);
> +
> +#endif
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [Qemu-devel] [PATCH v3 04/21] qapi: add QAPI visitor core
2011-06-15 14:33 ` Luiz Capitulino
@ 2011-06-15 14:54 ` Michael Roth
0 siblings, 0 replies; 37+ messages in thread
From: Michael Roth @ 2011-06-15 14:54 UTC (permalink / raw)
To: Luiz Capitulino; +Cc: aliguori, agl, qemu-devel, Jes.Sorensen
On 06/15/2011 09:33 AM, Luiz Capitulino wrote:
> On Mon, 13 Jun 2011 21:31:09 -0500
> Michael Roth<mdroth@linux.vnet.ibm.com> wrote:
>
>> Base definitions/includes for Visiter interface used by generated
>> visiter/marshalling code.
>>
>> Includes a GenericList type. Our lists require an embedded element.
>> Since these types are generated, if you want to use them in a different
>> type of data structure, there's no easy way to add another embedded
>> element. The solution is to have non-embedded lists and that what this is.
>>
>> Signed-off-by: Michael Roth<mdroth@linux.vnet.ibm.com>
>> ---
>> Makefile.objs | 6 +++
>> qapi/qapi-types-core.h | 21 ++++++++++
>> qapi/qapi-visit-core.c | 101 ++++++++++++++++++++++++++++++++++++++++++++++++
>> qapi/qapi-visit-core.h | 68 ++++++++++++++++++++++++++++++++
>> 4 files changed, 196 insertions(+), 0 deletions(-)
>> create mode 100644 qapi/qapi-types-core.h
>> create mode 100644 qapi/qapi-visit-core.c
>> create mode 100644 qapi/qapi-visit-core.h
>>
>> diff --git a/Makefile.objs b/Makefile.objs
>> index a7807e8..68d7b5a 100644
>> --- a/Makefile.objs
>> +++ b/Makefile.objs
>> @@ -364,6 +364,12 @@ endif
>>
>> libcacard-y = cac.o event.o vcard.o vreader.o vcard_emul_nss.o vcard_emul_type.o card_7816.o
>>
>> +######################################################################
>> +# qapi
>> +
>> +qapi-nested-y = qapi-visit-core.o
>> +qapi-obj-y = $(addprefix qapi/, $(qapi-nested-y))
>
> To build this I have to add qapi-obj-y to common-obj-y and add the
> qapi directory to the DIR variable in configure (so that it builds
> in a different directory).
Yah, nobody actually uses these right now except the unit tests/guest
agent so for test builds you have to manually add qapi-obj-y to another
target like qemu-img. I'll move the configure change to this patch in
the next run.
>
> I saw that you send the configure change in a different patch, but it
> has to be done here.
>
>> +
>> vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
>>
>> vl.o: QEMU_CFLAGS+=$(SDL_CFLAGS)
>> diff --git a/qapi/qapi-types-core.h b/qapi/qapi-types-core.h
>> new file mode 100644
>> index 0000000..de733ab
>> --- /dev/null
>> +++ b/qapi/qapi-types-core.h
>> @@ -0,0 +1,21 @@
>> +/*
>> + * Core Definitions for QAPI-generated Types
>> + *
>> + * Copyright IBM, Corp. 2011
>> + *
>> + * Authors:
>> + * Anthony Liguori<aliguori@us.ibm.com>
>> + *
>> + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
>> + * See the COPYING.LIB file in the top-level directory.
>> + *
>> + */
>> +
>> +#ifndef QAPI_TYPES_CORE_H
>> +#define QAPI_TYPES_CORE_H
>> +
>> +#include<stdbool.h>
>> +#include<stdint.h>
>> +#include "error.h"
>> +
>> +#endif
>> diff --git a/qapi/qapi-visit-core.c b/qapi/qapi-visit-core.c
>> new file mode 100644
>> index 0000000..948818e
>> --- /dev/null
>> +++ b/qapi/qapi-visit-core.c
>> @@ -0,0 +1,101 @@
>> +#include "qapi/qapi-visit-core.h"
>
> No license info.
>
Doh! Something about the term "copyright header" frequently causes me to
disregard non-.h files. These will all get fixed in the next run.
>> +
>> +void visit_start_handle(Visitor *v, void **obj, const char *kind, const char *name, Error **errp)
>> +{
>> + if (!error_is_set(errp)&& v->start_handle) {
>> + v->start_handle(v, obj, kind, name, errp);
>> + }
>> +}
>> +
>> +void visit_end_handle(Visitor *v, Error **errp)
>> +{
>> + if (!error_is_set(errp)&& v->end_handle) {
>> + v->end_handle(v, errp);
>> + }
>> +}
>> +
>> +void visit_start_struct(Visitor *v, void **obj, const char *kind, const char *name, size_t size, Error **errp)
>> +{
>> + if (!error_is_set(errp)) {
>> + v->start_struct(v, obj, kind, name, size, errp);
>> + }
>> +}
>> +
>> +void visit_end_struct(Visitor *v, Error **errp)
>> +{
>> + if (!error_is_set(errp)) {
>> + v->end_struct(v, errp);
>> + }
>> +}
>> +
>> +void visit_start_list(Visitor *v, const char *name, Error **errp)
>> +{
>> + if (!error_is_set(errp)) {
>> + v->start_list(v, name, errp);
>> + }
>> +}
>> +
>> +GenericList *visit_next_list(Visitor *v, GenericList **list, Error **errp)
>> +{
>> + if (!error_is_set(errp)) {
>> + return v->next_list(v, list, errp);
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +void visit_end_list(Visitor *v, Error **errp)
>> +{
>> + if (!error_is_set(errp)) {
>> + v->end_list(v, errp);
>> + }
>> +}
>> +
>> +void visit_start_optional(Visitor *v, bool *present, const char *name, Error **errp)
>> +{
>> + if (!error_is_set(errp)&& v->start_optional) {
>> + v->start_optional(v, present, name, errp);
>> + }
>> +}
>> +
>> +void visit_end_optional(Visitor *v, Error **errp)
>> +{
>> + if (!error_is_set(errp)&& v->end_optional) {
>> + v->end_optional(v, errp);
>> + }
>> +}
>> +
>> +void visit_type_enum(Visitor *v, int *obj, const char *kind, const char *name, Error **errp)
>> +{
>> + if (!error_is_set(errp)) {
>> + v->type_enum(v, obj, kind, name, errp);
>> + }
>> +}
>> +
>> +void visit_type_int(Visitor *v, int64_t *obj, const char *name, Error **errp)
>> +{
>> + if (!error_is_set(errp)) {
>> + v->type_int(v, obj, name, errp);
>> + }
>> +}
>> +
>> +void visit_type_bool(Visitor *v, bool *obj, const char *name, Error **errp)
>> +{
>> + if (!error_is_set(errp)) {
>> + v->type_bool(v, obj, name, errp);
>> + }
>> +}
>> +
>> +void visit_type_str(Visitor *v, char **obj, const char *name, Error **errp)
>> +{
>> + if (!error_is_set(errp)) {
>> + v->type_str(v, obj, name, errp);
>> + }
>> +}
>> +
>> +void visit_type_number(Visitor *v, double *obj, const char *name, Error **errp)
>> +{
>> + if (!error_is_set(errp)) {
>> + v->type_number(v, obj, name, errp);
>> + }
>> +}
>> diff --git a/qapi/qapi-visit-core.h b/qapi/qapi-visit-core.h
>> new file mode 100644
>> index 0000000..8350a6d
>> --- /dev/null
>> +++ b/qapi/qapi-visit-core.h
>> @@ -0,0 +1,68 @@
>> +/*
>> + * Core Definitions for QAPI Visitor Classes
>> + *
>> + * Copyright IBM, Corp. 2011
>> + *
>> + * Authors:
>> + * Anthony Liguori<aliguori@us.ibm.com>
>> + *
>> + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
>> + * See the COPYING.LIB file in the top-level directory.
>> + *
>> + */
>> +#ifndef QAPI_VISITOR_CORE_H
>> +#define QAPI_VISITOR_CORE_H
>> +
>> +#include "qapi/qapi-types-core.h"
>> +#include "error.h"
>> +#include<stdlib.h>
>> +
>> +typedef struct GenericList
>> +{
>> + void *value;
>> + struct GenericList *next;
>> +} GenericList;
>> +
>> +typedef struct Visitor Visitor;
>> +
>> +struct Visitor
>> +{
>> + /* Must be set */
>> + void (*start_struct)(Visitor *v, void **obj, const char *kind, const char *name, size_t size, Error **errp);
>> + void (*end_struct)(Visitor *v, Error **errp);
>> +
>> + void (*start_list)(Visitor *v, const char *name, Error **errp);
>> + GenericList *(*next_list)(Visitor *v, GenericList **list, Error **errp);
>> + void (*end_list)(Visitor *v, Error **errp);
>> +
>> + void (*type_enum)(Visitor *v, int *obj, const char *kind, const char *name, Error **errp);
>> +
>> + void (*type_int)(Visitor *v, int64_t *obj, const char *name, Error **errp);
>> + void (*type_bool)(Visitor *v, bool *obj, const char *name, Error **errp);
>> + void (*type_str)(Visitor *v, char **obj, const char *name, Error **errp);
>> + void (*type_number)(Visitor *v, double *obj, const char *name, Error **errp);
>> +
>> + /* May be NULL */
>> + void (*start_optional)(Visitor *v, bool *present, const char *name, Error **errp);
>> + void (*end_optional)(Visitor *v, Error **errp);
>> +
>> + void (*start_handle)(Visitor *v, void **obj, const char *kind, const char *name, Error **errp);
>> + void (*end_handle)(Visitor *v, Error **errp);
>> +};
>> +
>> +void visit_start_handle(Visitor *v, void **obj, const char *kind, const char *name, Error **errp);
>> +void visit_end_handle(Visitor *v, Error **errp);
>> +void visit_start_struct(Visitor *v, void **obj, const char *kind, const char *name, size_t size, Error **errp);
>> +void visit_end_struct(Visitor *v, Error **errp);
>> +void visit_start_list(Visitor *v, const char *name, Error **errp);
>> +GenericList *visit_next_list(Visitor *v, GenericList **list, Error **errp);
>> +void visit_end_list(Visitor *v, Error **errp);
>> +void visit_start_optional(Visitor *v, bool *present, const char *name, Error **errp);
>> +void visit_end_optional(Visitor *v, Error **errp);
>> +void visit_type_enum(Visitor *v, int *obj, const char *kind, const char *name, Error **errp);
>> +void visit_type_int(Visitor *v, int64_t *obj, const char *name, Error **errp);
>> +void visit_type_bool(Visitor *v, bool *obj, const char *name, Error **errp);
>> +void visit_type_str(Visitor *v, char **obj, const char *name, Error **errp);
>> +void visit_type_number(Visitor *v, double *obj, const char *name, Error **errp);
>> +
>> +#endif
>
^ permalink raw reply [flat|nested] 37+ messages in thread
* [Qemu-devel] [PATCH v3 05/21] qapi: add QMP input visitor
2011-06-14 2:31 [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v3 Michael Roth
` (3 preceding siblings ...)
2011-06-14 2:31 ` [Qemu-devel] [PATCH v3 04/21] qapi: add QAPI visitor core Michael Roth
@ 2011-06-14 2:31 ` Michael Roth
2011-06-15 16:11 ` Luiz Capitulino
2011-06-14 2:31 ` [Qemu-devel] [PATCH v3 06/21] qapi: add QMP output visitor Michael Roth
` (15 subsequent siblings)
20 siblings, 1 reply; 37+ messages in thread
From: Michael Roth @ 2011-06-14 2:31 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, Jes.Sorensen, agl, mdroth, lcapitulino
A type of Visiter class that is used to walk a qobject's
structure and assign each entry to the corresponding native C type.
Command marshaling function will use this to pull out QMP command
parameters recieved over the wire and pass them as native arguments
to the corresponding C functions.
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
Makefile.objs | 2 +-
qapi/qmp-input-visitor.c | 251 ++++++++++++++++++++++++++++++++++++++++++++++
qapi/qmp-input-visitor.h | 27 +++++
qerror.h | 3 +
4 files changed, 282 insertions(+), 1 deletions(-)
create mode 100644 qapi/qmp-input-visitor.c
create mode 100644 qapi/qmp-input-visitor.h
diff --git a/Makefile.objs b/Makefile.objs
index 68d7b5a..2eb90b8 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -367,7 +367,7 @@ libcacard-y = cac.o event.o vcard.o vreader.o vcard_emul_nss.o vcard_emul_type.o
######################################################################
# qapi
-qapi-nested-y = qapi-visit-core.o
+qapi-nested-y = qapi-visit-core.o qmp-input-visitor.o
qapi-obj-y = $(addprefix qapi/, $(qapi-nested-y))
vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
diff --git a/qapi/qmp-input-visitor.c b/qapi/qmp-input-visitor.c
new file mode 100644
index 0000000..9344d37
--- /dev/null
+++ b/qapi/qmp-input-visitor.c
@@ -0,0 +1,251 @@
+#include "qmp-input-visitor.h"
+#include "qemu-queue.h"
+#include "qemu-common.h"
+#include "qemu-objects.h"
+#include "qerror.h"
+
+#define QIV_STACK_SIZE 1024
+
+typedef struct StackObject
+{
+ QObject *obj;
+ const QListEntry *entry;
+} StackObject;
+
+struct QmpInputVisitor
+{
+ Visitor visitor;
+ QObject *obj;
+ StackObject stack[QIV_STACK_SIZE];
+ int nb_stack;
+};
+
+static QmpInputVisitor *to_qiv(Visitor *v)
+{
+ return container_of(v, QmpInputVisitor, visitor);
+}
+
+static QObject *qmp_input_get_object(QmpInputVisitor *qiv, const char *name)
+{
+ QObject *qobj;
+
+ if (qiv->nb_stack == 0) {
+ qobj = qiv->obj;
+ } else {
+ qobj = qiv->stack[qiv->nb_stack - 1].obj;
+ }
+
+ if (name && qobject_type(qobj) == QTYPE_QDICT) {
+ return qdict_get(qobject_to_qdict(qobj), name);
+ } else if (qiv->nb_stack > 0 && qobject_type(qobj) == QTYPE_QLIST) {
+ return qlist_entry_obj(qiv->stack[qiv->nb_stack - 1].entry);
+ }
+
+ return qobj;
+}
+
+static void qmp_input_push(QmpInputVisitor *qiv, QObject *obj, Error **errp)
+{
+ qiv->stack[qiv->nb_stack].obj = obj;
+ if (qobject_type(obj) == QTYPE_QLIST) {
+ qiv->stack[qiv->nb_stack].entry = qlist_first(qobject_to_qlist(obj));
+ }
+ qiv->nb_stack++;
+
+ if (qiv->nb_stack >= QIV_STACK_SIZE) {
+ error_set(errp, QERR_QAPI_VISITOR_STACK_OVERRUN);
+ return;
+ }
+}
+
+static void qmp_input_pop(QmpInputVisitor *qiv, Error **errp)
+{
+ qiv->nb_stack--;
+ if (qiv->nb_stack < 0) {
+ error_set(errp, QERR_QAPI_VISITOR_STACK_OVERRUN);
+ return;
+ }
+}
+
+static void qmp_input_start_struct(Visitor *v, void **obj, const char *kind, const char *name, size_t size, Error **errp)
+{
+ QmpInputVisitor *qiv = to_qiv(v);
+ QObject *qobj = qmp_input_get_object(qiv, name);
+
+ if (!qobj || qobject_type(qobj) != QTYPE_QDICT) {
+ error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "QDict");
+ return;
+ }
+
+ qmp_input_push(qiv, qobj, errp);
+ if (error_is_set(errp)) {
+ return;
+ }
+
+ if (obj) {
+ *obj = qemu_mallocz(size);
+ }
+}
+
+static void qmp_input_end_struct(Visitor *v, Error **errp)
+{
+ QmpInputVisitor *qiv = to_qiv(v);
+
+ qmp_input_pop(qiv, errp);
+}
+
+static void qmp_input_start_list(Visitor *v, const char *name, Error **errp)
+{
+ QmpInputVisitor *qiv = to_qiv(v);
+ QObject *qobj = qmp_input_get_object(qiv, name);
+
+ if (!qobj || qobject_type(qobj) != QTYPE_QLIST) {
+ error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "list");
+ return;
+ }
+
+ qmp_input_push(qiv, qobj, errp);
+}
+
+static GenericList *qmp_input_next_list(Visitor *v, GenericList **list, Error **errp)
+{
+ QmpInputVisitor *qiv = to_qiv(v);
+ GenericList *entry;
+ StackObject *so = &qiv->stack[qiv->nb_stack - 1];
+
+ if (so->entry == NULL) {
+ return NULL;
+ }
+
+ entry = qemu_mallocz(sizeof(*entry));
+ if (*list) {
+ so->entry = qlist_next(so->entry);
+ if (so->entry == NULL) {
+ qemu_free(entry);
+ return NULL;
+ }
+ (*list)->next = entry;
+ }
+ *list = entry;
+
+
+ return entry;
+}
+
+static void qmp_input_end_list(Visitor *v, Error **errp)
+{
+ QmpInputVisitor *qiv = to_qiv(v);
+
+ qmp_input_pop(qiv, errp);
+}
+
+static void qmp_input_type_int(Visitor *v, int64_t *obj, const char *name, Error **errp)
+{
+ QmpInputVisitor *qiv = to_qiv(v);
+ QObject *qobj = qmp_input_get_object(qiv, name);
+
+ if (!qobj || qobject_type(qobj) != QTYPE_QINT) {
+ error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "integer");
+ return;
+ }
+
+ *obj = qint_get_int(qobject_to_qint(qobj));
+}
+
+static void qmp_input_type_bool(Visitor *v, bool *obj, const char *name, Error **errp)
+{
+ QmpInputVisitor *qiv = to_qiv(v);
+ QObject *qobj = qmp_input_get_object(qiv, name);
+
+ if (!qobj || qobject_type(qobj) != QTYPE_QBOOL) {
+ error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "boolean");
+ return;
+ }
+
+ *obj = qbool_get_int(qobject_to_qbool(qobj));
+}
+
+static void qmp_input_type_str(Visitor *v, char **obj, const char *name, Error **errp)
+{
+ QmpInputVisitor *qiv = to_qiv(v);
+ QObject *qobj = qmp_input_get_object(qiv, name);
+
+ if (!qobj || qobject_type(qobj) != QTYPE_QSTRING) {
+ error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "string");
+ return;
+ }
+
+ *obj = qemu_strdup(qstring_get_str(qobject_to_qstring(qobj)));
+}
+
+static void qmp_input_type_number(Visitor *v, double *obj, const char *name, Error **errp)
+{
+ QmpInputVisitor *qiv = to_qiv(v);
+ QObject *qobj = qmp_input_get_object(qiv, name);
+
+ if (!qobj || qobject_type(qobj) != QTYPE_QFLOAT) {
+ error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "double");
+ return;
+ }
+
+ *obj = qfloat_get_double(qobject_to_qfloat(qobj));
+}
+
+static void qmp_input_type_enum(Visitor *v, int *obj, const char *kind, const char *name, Error **errp)
+{
+ int64_t value;
+ qmp_input_type_int(v, &value, name, errp);
+ *obj = value;
+}
+
+static void qmp_input_start_optional(Visitor *v, bool *present,
+ const char *name, Error **errp)
+{
+ QmpInputVisitor *qiv = to_qiv(v);
+ QObject *qobj = qmp_input_get_object(qiv, name);
+
+ if (!qobj) {
+ *present = false;
+ return;
+ }
+
+ *present = true;
+}
+
+static void qmp_input_end_optional(Visitor *v, Error **errp)
+{
+}
+
+Visitor *qmp_input_get_visitor(QmpInputVisitor *v)
+{
+ return &v->visitor;
+}
+
+void qmp_input_visitor_cleanup(QmpInputVisitor *v)
+{
+ qemu_free(v);
+}
+
+QmpInputVisitor *qmp_input_visitor_new(QObject *obj)
+{
+ QmpInputVisitor *v;
+
+ v = qemu_mallocz(sizeof(*v));
+
+ v->visitor.start_struct = qmp_input_start_struct;
+ v->visitor.end_struct = qmp_input_end_struct;
+ v->visitor.start_list = qmp_input_start_list;
+ v->visitor.next_list = qmp_input_next_list;
+ v->visitor.end_list = qmp_input_end_list;
+ v->visitor.type_enum = qmp_input_type_enum;
+ v->visitor.type_int = qmp_input_type_int;
+ v->visitor.type_bool = qmp_input_type_bool;
+ v->visitor.type_str = qmp_input_type_str;
+ v->visitor.type_number = qmp_input_type_number;
+ v->visitor.start_optional = qmp_input_start_optional;
+ v->visitor.end_optional = qmp_input_end_optional;
+
+ v->obj = obj;
+
+ return v;
+}
diff --git a/qapi/qmp-input-visitor.h b/qapi/qmp-input-visitor.h
new file mode 100644
index 0000000..3f798f0
--- /dev/null
+++ b/qapi/qmp-input-visitor.h
@@ -0,0 +1,27 @@
+/*
+ * Input Visitor
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#ifndef QMP_INPUT_VISITOR_H
+#define QMP_INPUT_VISITOR_H
+
+#include "qapi-visit-core.h"
+#include "qobject.h"
+
+typedef struct QmpInputVisitor QmpInputVisitor;
+
+QmpInputVisitor *qmp_input_visitor_new(QObject *obj);
+void qmp_input_visitor_cleanup(QmpInputVisitor *v);
+
+Visitor *qmp_input_get_visitor(QmpInputVisitor *v);
+
+#endif
diff --git a/qerror.h b/qerror.h
index 16c830d..7a89a50 100644
--- a/qerror.h
+++ b/qerror.h
@@ -124,6 +124,9 @@ QError *qobject_to_qerror(const QObject *obj);
#define QERR_JSON_PARSE_ERROR \
"{ 'class': 'JSONParseError', 'data': { 'message': %s } }"
+#define QERR_QAPI_VISITOR_STACK_OVERRUN \
+ "{ 'class': 'QAPIVisitorStackOverrun', 'data': {} }"
+
#define QERR_KVM_MISSING_CAP \
"{ 'class': 'KVMMissingCap', 'data': { 'capability': %s, 'feature': %s } }"
--
1.7.0.4
^ permalink raw reply related [flat|nested] 37+ messages in thread
* Re: [Qemu-devel] [PATCH v3 05/21] qapi: add QMP input visitor
2011-06-14 2:31 ` [Qemu-devel] [PATCH v3 05/21] qapi: add QMP input visitor Michael Roth
@ 2011-06-15 16:11 ` Luiz Capitulino
2011-06-15 16:56 ` Michael Roth
0 siblings, 1 reply; 37+ messages in thread
From: Luiz Capitulino @ 2011-06-15 16:11 UTC (permalink / raw)
To: Michael Roth; +Cc: aliguori, agl, qemu-devel, Jes.Sorensen
On Mon, 13 Jun 2011 21:31:10 -0500
Michael Roth <mdroth@linux.vnet.ibm.com> wrote:
> A type of Visiter class that is used to walk a qobject's
> structure and assign each entry to the corresponding native C type.
> Command marshaling function will use this to pull out QMP command
> parameters recieved over the wire and pass them as native arguments
> to the corresponding C functions.
>
> Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
> ---
> Makefile.objs | 2 +-
> qapi/qmp-input-visitor.c | 251 ++++++++++++++++++++++++++++++++++++++++++++++
> qapi/qmp-input-visitor.h | 27 +++++
> qerror.h | 3 +
> 4 files changed, 282 insertions(+), 1 deletions(-)
> create mode 100644 qapi/qmp-input-visitor.c
> create mode 100644 qapi/qmp-input-visitor.h
>
> diff --git a/Makefile.objs b/Makefile.objs
> index 68d7b5a..2eb90b8 100644
> --- a/Makefile.objs
> +++ b/Makefile.objs
> @@ -367,7 +367,7 @@ libcacard-y = cac.o event.o vcard.o vreader.o vcard_emul_nss.o vcard_emul_type.o
> ######################################################################
> # qapi
>
> -qapi-nested-y = qapi-visit-core.o
> +qapi-nested-y = qapi-visit-core.o qmp-input-visitor.o
> qapi-obj-y = $(addprefix qapi/, $(qapi-nested-y))
>
> vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
> diff --git a/qapi/qmp-input-visitor.c b/qapi/qmp-input-visitor.c
> new file mode 100644
> index 0000000..9344d37
> --- /dev/null
> +++ b/qapi/qmp-input-visitor.c
No license info. It seems to be missing in more files.
> @@ -0,0 +1,251 @@
> +#include "qmp-input-visitor.h"
> +#include "qemu-queue.h"
> +#include "qemu-common.h"
> +#include "qemu-objects.h"
> +#include "qerror.h"
> +
> +#define QIV_STACK_SIZE 1024
> +
> +typedef struct StackObject
> +{
> + QObject *obj;
> + const QListEntry *entry;
> +} StackObject;
> +
> +struct QmpInputVisitor
> +{
> + Visitor visitor;
> + QObject *obj;
> + StackObject stack[QIV_STACK_SIZE];
> + int nb_stack;
> +};
> +
> +static QmpInputVisitor *to_qiv(Visitor *v)
> +{
> + return container_of(v, QmpInputVisitor, visitor);
> +}
> +
> +static QObject *qmp_input_get_object(QmpInputVisitor *qiv, const char *name)
> +{
> + QObject *qobj;
> +
> + if (qiv->nb_stack == 0) {
> + qobj = qiv->obj;
> + } else {
> + qobj = qiv->stack[qiv->nb_stack - 1].obj;
> + }
> +
> + if (name && qobject_type(qobj) == QTYPE_QDICT) {
> + return qdict_get(qobject_to_qdict(qobj), name);
> + } else if (qiv->nb_stack > 0 && qobject_type(qobj) == QTYPE_QLIST) {
> + return qlist_entry_obj(qiv->stack[qiv->nb_stack - 1].entry);
> + }
> +
> + return qobj;
> +}
> +
> +static void qmp_input_push(QmpInputVisitor *qiv, QObject *obj, Error **errp)
> +{
> + qiv->stack[qiv->nb_stack].obj = obj;
> + if (qobject_type(obj) == QTYPE_QLIST) {
> + qiv->stack[qiv->nb_stack].entry = qlist_first(qobject_to_qlist(obj));
> + }
> + qiv->nb_stack++;
> +
> + if (qiv->nb_stack >= QIV_STACK_SIZE) {
> + error_set(errp, QERR_QAPI_VISITOR_STACK_OVERRUN);
QAPI is something internal to qemu, the error name and description
should be more generic like "not enough memory" or "not enough space".
> + return;
> + }
> +}
> +
> +static void qmp_input_pop(QmpInputVisitor *qiv, Error **errp)
> +{
> + qiv->nb_stack--;
> + if (qiv->nb_stack < 0) {
> + error_set(errp, QERR_QAPI_VISITOR_STACK_OVERRUN);
> + return;
> + }
> +}
> +
> +static void qmp_input_start_struct(Visitor *v, void **obj, const char *kind, const char *name, size_t size, Error **errp)
> +{
> + QmpInputVisitor *qiv = to_qiv(v);
> + QObject *qobj = qmp_input_get_object(qiv, name);
> +
> + if (!qobj || qobject_type(qobj) != QTYPE_QDICT) {
> + error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "QDict");
> + return;
> + }
> +
> + qmp_input_push(qiv, qobj, errp);
> + if (error_is_set(errp)) {
> + return;
> + }
> +
> + if (obj) {
> + *obj = qemu_mallocz(size);
> + }
> +}
> +
> +static void qmp_input_end_struct(Visitor *v, Error **errp)
> +{
> + QmpInputVisitor *qiv = to_qiv(v);
> +
> + qmp_input_pop(qiv, errp);
> +}
> +
> +static void qmp_input_start_list(Visitor *v, const char *name, Error **errp)
> +{
> + QmpInputVisitor *qiv = to_qiv(v);
> + QObject *qobj = qmp_input_get_object(qiv, name);
> +
> + if (!qobj || qobject_type(qobj) != QTYPE_QLIST) {
> + error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "list");
> + return;
> + }
> +
> + qmp_input_push(qiv, qobj, errp);
> +}
> +
> +static GenericList *qmp_input_next_list(Visitor *v, GenericList **list, Error **errp)
> +{
> + QmpInputVisitor *qiv = to_qiv(v);
> + GenericList *entry;
> + StackObject *so = &qiv->stack[qiv->nb_stack - 1];
> +
> + if (so->entry == NULL) {
> + return NULL;
> + }
> +
> + entry = qemu_mallocz(sizeof(*entry));
> + if (*list) {
> + so->entry = qlist_next(so->entry);
> + if (so->entry == NULL) {
> + qemu_free(entry);
> + return NULL;
> + }
> + (*list)->next = entry;
> + }
> + *list = entry;
> +
> +
> + return entry;
> +}
> +
> +static void qmp_input_end_list(Visitor *v, Error **errp)
> +{
> + QmpInputVisitor *qiv = to_qiv(v);
> +
> + qmp_input_pop(qiv, errp);
> +}
> +
> +static void qmp_input_type_int(Visitor *v, int64_t *obj, const char *name, Error **errp)
> +{
> + QmpInputVisitor *qiv = to_qiv(v);
> + QObject *qobj = qmp_input_get_object(qiv, name);
> +
> + if (!qobj || qobject_type(qobj) != QTYPE_QINT) {
> + error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "integer");
> + return;
> + }
> +
> + *obj = qint_get_int(qobject_to_qint(qobj));
> +}
> +
> +static void qmp_input_type_bool(Visitor *v, bool *obj, const char *name, Error **errp)
> +{
> + QmpInputVisitor *qiv = to_qiv(v);
> + QObject *qobj = qmp_input_get_object(qiv, name);
> +
> + if (!qobj || qobject_type(qobj) != QTYPE_QBOOL) {
> + error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "boolean");
> + return;
> + }
> +
> + *obj = qbool_get_int(qobject_to_qbool(qobj));
> +}
> +
> +static void qmp_input_type_str(Visitor *v, char **obj, const char *name, Error **errp)
> +{
> + QmpInputVisitor *qiv = to_qiv(v);
> + QObject *qobj = qmp_input_get_object(qiv, name);
> +
> + if (!qobj || qobject_type(qobj) != QTYPE_QSTRING) {
> + error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "string");
> + return;
> + }
> +
> + *obj = qemu_strdup(qstring_get_str(qobject_to_qstring(qobj)));
> +}
> +
> +static void qmp_input_type_number(Visitor *v, double *obj, const char *name, Error **errp)
> +{
> + QmpInputVisitor *qiv = to_qiv(v);
> + QObject *qobj = qmp_input_get_object(qiv, name);
> +
> + if (!qobj || qobject_type(qobj) != QTYPE_QFLOAT) {
> + error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "double");
> + return;
> + }
> +
> + *obj = qfloat_get_double(qobject_to_qfloat(qobj));
> +}
> +
> +static void qmp_input_type_enum(Visitor *v, int *obj, const char *kind, const char *name, Error **errp)
> +{
> + int64_t value;
> + qmp_input_type_int(v, &value, name, errp);
> + *obj = value;
> +}
> +
> +static void qmp_input_start_optional(Visitor *v, bool *present,
> + const char *name, Error **errp)
> +{
> + QmpInputVisitor *qiv = to_qiv(v);
> + QObject *qobj = qmp_input_get_object(qiv, name);
> +
> + if (!qobj) {
> + *present = false;
> + return;
> + }
> +
> + *present = true;
> +}
> +
> +static void qmp_input_end_optional(Visitor *v, Error **errp)
> +{
> +}
> +
> +Visitor *qmp_input_get_visitor(QmpInputVisitor *v)
> +{
> + return &v->visitor;
> +}
> +
> +void qmp_input_visitor_cleanup(QmpInputVisitor *v)
> +{
You're not decrementing the reference to v->obj. Actually, we should also
increment the reference to it before storing or document that the reference
ownership is transferred to this function.
> + qemu_free(v);
> +}
> +
> +QmpInputVisitor *qmp_input_visitor_new(QObject *obj)
> +{
> + QmpInputVisitor *v;
> +
> + v = qemu_mallocz(sizeof(*v));
> +
> + v->visitor.start_struct = qmp_input_start_struct;
> + v->visitor.end_struct = qmp_input_end_struct;
> + v->visitor.start_list = qmp_input_start_list;
> + v->visitor.next_list = qmp_input_next_list;
> + v->visitor.end_list = qmp_input_end_list;
> + v->visitor.type_enum = qmp_input_type_enum;
> + v->visitor.type_int = qmp_input_type_int;
> + v->visitor.type_bool = qmp_input_type_bool;
> + v->visitor.type_str = qmp_input_type_str;
> + v->visitor.type_number = qmp_input_type_number;
> + v->visitor.start_optional = qmp_input_start_optional;
> + v->visitor.end_optional = qmp_input_end_optional;
> +
> + v->obj = obj;
> +
> + return v;
> +}
> diff --git a/qapi/qmp-input-visitor.h b/qapi/qmp-input-visitor.h
> new file mode 100644
> index 0000000..3f798f0
> --- /dev/null
> +++ b/qapi/qmp-input-visitor.h
> @@ -0,0 +1,27 @@
> +/*
> + * Input Visitor
> + *
> + * Copyright IBM, Corp. 2011
> + *
> + * Authors:
> + * Anthony Liguori <aliguori@us.ibm.com>
> + *
> + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
> + * See the COPYING.LIB file in the top-level directory.
> + *
> + */
> +
> +#ifndef QMP_INPUT_VISITOR_H
> +#define QMP_INPUT_VISITOR_H
> +
> +#include "qapi-visit-core.h"
> +#include "qobject.h"
> +
> +typedef struct QmpInputVisitor QmpInputVisitor;
> +
> +QmpInputVisitor *qmp_input_visitor_new(QObject *obj);
> +void qmp_input_visitor_cleanup(QmpInputVisitor *v);
> +
> +Visitor *qmp_input_get_visitor(QmpInputVisitor *v);
> +
> +#endif
> diff --git a/qerror.h b/qerror.h
> index 16c830d..7a89a50 100644
> --- a/qerror.h
> +++ b/qerror.h
> @@ -124,6 +124,9 @@ QError *qobject_to_qerror(const QObject *obj);
> #define QERR_JSON_PARSE_ERROR \
> "{ 'class': 'JSONParseError', 'data': { 'message': %s } }"
>
> +#define QERR_QAPI_VISITOR_STACK_OVERRUN \
> + "{ 'class': 'QAPIVisitorStackOverrun', 'data': {} }"
> +
> #define QERR_KVM_MISSING_CAP \
> "{ 'class': 'KVMMissingCap', 'data': { 'capability': %s, 'feature': %s } }"
>
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [Qemu-devel] [PATCH v3 05/21] qapi: add QMP input visitor
2011-06-15 16:11 ` Luiz Capitulino
@ 2011-06-15 16:56 ` Michael Roth
2011-06-15 17:02 ` Luiz Capitulino
0 siblings, 1 reply; 37+ messages in thread
From: Michael Roth @ 2011-06-15 16:56 UTC (permalink / raw)
To: Luiz Capitulino; +Cc: aliguori, agl, qemu-devel, Jes.Sorensen
On 06/15/2011 11:11 AM, Luiz Capitulino wrote:
> On Mon, 13 Jun 2011 21:31:10 -0500
> Michael Roth<mdroth@linux.vnet.ibm.com> wrote:
>
<snip>
>> +Visitor *qmp_input_get_visitor(QmpInputVisitor *v)
>> +{
>> + return&v->visitor;
>> +}
>> +
>> +void qmp_input_visitor_cleanup(QmpInputVisitor *v)
>> +{
>
> You're not decrementing the reference to v->obj. Actually, we should also
> increment the reference to it before storing or document that the reference
> ownership is transferred to this function.
>
Ownership never gets transferred to the visitor in the dispatch path;
the caller is supposed to free it. I thought there was some manipulation
elsewhere that prevented us from using a const argument to
qmp_input_visitor_new() instead, but it looks like we can. Otherwise,
I'd prefer to do an inc+dec to make this more explicit.
>> + qemu_free(v);
>> +}
>> +
>> +QmpInputVisitor *qmp_input_visitor_new(QObject *obj)
>> +{
>> + QmpInputVisitor *v;
>> +
>> + v = qemu_mallocz(sizeof(*v));
>> +
>> + v->visitor.start_struct = qmp_input_start_struct;
>> + v->visitor.end_struct = qmp_input_end_struct;
>> + v->visitor.start_list = qmp_input_start_list;
>> + v->visitor.next_list = qmp_input_next_list;
>> + v->visitor.end_list = qmp_input_end_list;
>> + v->visitor.type_enum = qmp_input_type_enum;
>> + v->visitor.type_int = qmp_input_type_int;
>> + v->visitor.type_bool = qmp_input_type_bool;
>> + v->visitor.type_str = qmp_input_type_str;
>> + v->visitor.type_number = qmp_input_type_number;
>> + v->visitor.start_optional = qmp_input_start_optional;
>> + v->visitor.end_optional = qmp_input_end_optional;
>> +
>> + v->obj = obj;
>> +
>> + return v;
>> +}
>> diff --git a/qapi/qmp-input-visitor.h b/qapi/qmp-input-visitor.h
>> new file mode 100644
>> index 0000000..3f798f0
>> --- /dev/null
>> +++ b/qapi/qmp-input-visitor.h
>> @@ -0,0 +1,27 @@
>> +/*
>> + * Input Visitor
>> + *
>> + * Copyright IBM, Corp. 2011
>> + *
>> + * Authors:
>> + * Anthony Liguori<aliguori@us.ibm.com>
>> + *
>> + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
>> + * See the COPYING.LIB file in the top-level directory.
>> + *
>> + */
>> +
>> +#ifndef QMP_INPUT_VISITOR_H
>> +#define QMP_INPUT_VISITOR_H
>> +
>> +#include "qapi-visit-core.h"
>> +#include "qobject.h"
>> +
>> +typedef struct QmpInputVisitor QmpInputVisitor;
>> +
>> +QmpInputVisitor *qmp_input_visitor_new(QObject *obj);
>> +void qmp_input_visitor_cleanup(QmpInputVisitor *v);
>> +
>> +Visitor *qmp_input_get_visitor(QmpInputVisitor *v);
>> +
>> +#endif
>> diff --git a/qerror.h b/qerror.h
>> index 16c830d..7a89a50 100644
>> --- a/qerror.h
>> +++ b/qerror.h
>> @@ -124,6 +124,9 @@ QError *qobject_to_qerror(const QObject *obj);
>> #define QERR_JSON_PARSE_ERROR \
>> "{ 'class': 'JSONParseError', 'data': { 'message': %s } }"
>>
>> +#define QERR_QAPI_VISITOR_STACK_OVERRUN \
>> + "{ 'class': 'QAPIVisitorStackOverrun', 'data': {} }"
>> +
>> #define QERR_KVM_MISSING_CAP \
>> "{ 'class': 'KVMMissingCap', 'data': { 'capability': %s, 'feature': %s } }"
>>
>
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [Qemu-devel] [PATCH v3 05/21] qapi: add QMP input visitor
2011-06-15 16:56 ` Michael Roth
@ 2011-06-15 17:02 ` Luiz Capitulino
0 siblings, 0 replies; 37+ messages in thread
From: Luiz Capitulino @ 2011-06-15 17:02 UTC (permalink / raw)
To: Michael Roth; +Cc: aliguori, agl, qemu-devel, Jes.Sorensen
On Wed, 15 Jun 2011 11:56:03 -0500
Michael Roth <mdroth@linux.vnet.ibm.com> wrote:
> On 06/15/2011 11:11 AM, Luiz Capitulino wrote:
> > On Mon, 13 Jun 2011 21:31:10 -0500
> > Michael Roth<mdroth@linux.vnet.ibm.com> wrote:
> >
> <snip>
> >> +Visitor *qmp_input_get_visitor(QmpInputVisitor *v)
> >> +{
> >> + return&v->visitor;
> >> +}
> >> +
> >> +void qmp_input_visitor_cleanup(QmpInputVisitor *v)
> >> +{
> >
> > You're not decrementing the reference to v->obj. Actually, we should also
> > increment the reference to it before storing or document that the reference
> > ownership is transferred to this function.
> >
>
> Ownership never gets transferred to the visitor in the dispatch path;
> the caller is supposed to free it. I thought there was some manipulation
> elsewhere that prevented us from using a const argument to
> qmp_input_visitor_new() instead, but it looks like we can. Otherwise,
> I'd prefer to do an inc+dec to make this more explicit.
Yeah, I prefer that too.
>
> >> + qemu_free(v);
> >> +}
> >> +
> >> +QmpInputVisitor *qmp_input_visitor_new(QObject *obj)
> >> +{
> >> + QmpInputVisitor *v;
> >> +
> >> + v = qemu_mallocz(sizeof(*v));
> >> +
> >> + v->visitor.start_struct = qmp_input_start_struct;
> >> + v->visitor.end_struct = qmp_input_end_struct;
> >> + v->visitor.start_list = qmp_input_start_list;
> >> + v->visitor.next_list = qmp_input_next_list;
> >> + v->visitor.end_list = qmp_input_end_list;
> >> + v->visitor.type_enum = qmp_input_type_enum;
> >> + v->visitor.type_int = qmp_input_type_int;
> >> + v->visitor.type_bool = qmp_input_type_bool;
> >> + v->visitor.type_str = qmp_input_type_str;
> >> + v->visitor.type_number = qmp_input_type_number;
> >> + v->visitor.start_optional = qmp_input_start_optional;
> >> + v->visitor.end_optional = qmp_input_end_optional;
> >> +
> >> + v->obj = obj;
> >> +
> >> + return v;
> >> +}
> >> diff --git a/qapi/qmp-input-visitor.h b/qapi/qmp-input-visitor.h
> >> new file mode 100644
> >> index 0000000..3f798f0
> >> --- /dev/null
> >> +++ b/qapi/qmp-input-visitor.h
> >> @@ -0,0 +1,27 @@
> >> +/*
> >> + * Input Visitor
> >> + *
> >> + * Copyright IBM, Corp. 2011
> >> + *
> >> + * Authors:
> >> + * Anthony Liguori<aliguori@us.ibm.com>
> >> + *
> >> + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
> >> + * See the COPYING.LIB file in the top-level directory.
> >> + *
> >> + */
> >> +
> >> +#ifndef QMP_INPUT_VISITOR_H
> >> +#define QMP_INPUT_VISITOR_H
> >> +
> >> +#include "qapi-visit-core.h"
> >> +#include "qobject.h"
> >> +
> >> +typedef struct QmpInputVisitor QmpInputVisitor;
> >> +
> >> +QmpInputVisitor *qmp_input_visitor_new(QObject *obj);
> >> +void qmp_input_visitor_cleanup(QmpInputVisitor *v);
> >> +
> >> +Visitor *qmp_input_get_visitor(QmpInputVisitor *v);
> >> +
> >> +#endif
> >> diff --git a/qerror.h b/qerror.h
> >> index 16c830d..7a89a50 100644
> >> --- a/qerror.h
> >> +++ b/qerror.h
> >> @@ -124,6 +124,9 @@ QError *qobject_to_qerror(const QObject *obj);
> >> #define QERR_JSON_PARSE_ERROR \
> >> "{ 'class': 'JSONParseError', 'data': { 'message': %s } }"
> >>
> >> +#define QERR_QAPI_VISITOR_STACK_OVERRUN \
> >> + "{ 'class': 'QAPIVisitorStackOverrun', 'data': {} }"
> >> +
> >> #define QERR_KVM_MISSING_CAP \
> >> "{ 'class': 'KVMMissingCap', 'data': { 'capability': %s, 'feature': %s } }"
> >>
> >
>
^ permalink raw reply [flat|nested] 37+ messages in thread
* [Qemu-devel] [PATCH v3 06/21] qapi: add QMP output visitor
2011-06-14 2:31 [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v3 Michael Roth
` (4 preceding siblings ...)
2011-06-14 2:31 ` [Qemu-devel] [PATCH v3 05/21] qapi: add QMP input visitor Michael Roth
@ 2011-06-14 2:31 ` Michael Roth
2011-06-14 2:31 ` [Qemu-devel] [PATCH v3 07/21] qapi: add QAPI dealloc visitor Michael Roth
` (14 subsequent siblings)
20 siblings, 0 replies; 37+ messages in thread
From: Michael Roth @ 2011-06-14 2:31 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, Jes.Sorensen, agl, mdroth, lcapitulino
Type of Visiter class that serves as the inverse of the input visitor:
it takes a series of native C types and uses their values to construct a
corresponding QObject. The command marshaling/dispatcher functions will
use this to convert the output of QMP functions into a QObject that can
be sent over the wire.
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
Makefile.objs | 2 +-
qapi/qmp-output-visitor.c | 199 +++++++++++++++++++++++++++++++++++++++++++++
qapi/qmp-output-visitor.h | 28 +++++++
3 files changed, 228 insertions(+), 1 deletions(-)
create mode 100644 qapi/qmp-output-visitor.c
create mode 100644 qapi/qmp-output-visitor.h
diff --git a/Makefile.objs b/Makefile.objs
index 2eb90b8..af302ea 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -367,7 +367,7 @@ libcacard-y = cac.o event.o vcard.o vreader.o vcard_emul_nss.o vcard_emul_type.o
######################################################################
# qapi
-qapi-nested-y = qapi-visit-core.o qmp-input-visitor.o
+qapi-nested-y = qapi-visit-core.o qmp-input-visitor.o qmp-output-visitor.o
qapi-obj-y = $(addprefix qapi/, $(qapi-nested-y))
vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
diff --git a/qapi/qmp-output-visitor.c b/qapi/qmp-output-visitor.c
new file mode 100644
index 0000000..30c8c6f
--- /dev/null
+++ b/qapi/qmp-output-visitor.c
@@ -0,0 +1,199 @@
+#include "qmp-output-visitor.h"
+#include "qemu-queue.h"
+#include "qemu-common.h"
+#include "qemu-objects.h"
+
+typedef struct QStackEntry
+{
+ QObject *value;
+ QTAILQ_ENTRY(QStackEntry) node;
+} QStackEntry;
+
+typedef QTAILQ_HEAD(QStack, QStackEntry) QStack;
+
+struct QmpOutputVisitor
+{
+ Visitor visitor;
+ QStack stack;
+};
+
+#define qmp_output_add(qov, name, value) qmp_output_add_obj(qov, name, QOBJECT(value))
+#define qmp_output_push(qov, value) qmp_output_push_obj(qov, QOBJECT(value))
+
+static QmpOutputVisitor *to_qov(Visitor *v)
+{
+ return container_of(v, QmpOutputVisitor, visitor);
+}
+
+static void qmp_output_push_obj(QmpOutputVisitor *qov, QObject *value)
+{
+ QStackEntry *e = qemu_mallocz(sizeof(*e));
+
+ e->value = value;
+ QTAILQ_INSERT_HEAD(&qov->stack, e, node);
+}
+
+static QObject *qmp_output_pop(QmpOutputVisitor *qov)
+{
+ QStackEntry *e = QTAILQ_FIRST(&qov->stack);
+ QObject *value;
+ QTAILQ_REMOVE(&qov->stack, e, node);
+ value = e->value;
+ qemu_free(e);
+ return value;
+}
+
+static QObject *qmp_output_first(QmpOutputVisitor *qov)
+{
+ QStackEntry *e = QTAILQ_LAST(&qov->stack, QStack);
+ return e->value;
+}
+
+static QObject *qmp_output_last(QmpOutputVisitor *qov)
+{
+ QStackEntry *e = QTAILQ_FIRST(&qov->stack);
+ return e->value;
+}
+
+static void qmp_output_add_obj(QmpOutputVisitor *qov, const char *name, QObject *value)
+{
+ QObject *cur;
+
+ if (QTAILQ_EMPTY(&qov->stack)) {
+ qmp_output_push_obj(qov, value);
+ return;
+ }
+
+ cur = qmp_output_last(qov);
+
+ switch (qobject_type(cur)) {
+ case QTYPE_QDICT:
+ qdict_put_obj(qobject_to_qdict(cur), name, value);
+ break;
+ case QTYPE_QLIST:
+ qlist_append_obj(qobject_to_qlist(cur), value);
+ break;
+ default:
+ qobject_decref(qmp_output_pop(qov));
+ qmp_output_push_obj(qov, value);
+ break;
+ }
+}
+
+static void qmp_output_start_struct(Visitor *v, void **obj, const char *kind, const char *name, size_t unused, Error **errp)
+{
+ QmpOutputVisitor *qov = to_qov(v);
+ QDict *dict = qdict_new();
+
+ qmp_output_add(qov, name, dict);
+ qmp_output_push(qov, dict);
+}
+
+static void qmp_output_end_struct(Visitor *v, Error **errp)
+{
+ QmpOutputVisitor *qov = to_qov(v);
+ qmp_output_pop(qov);
+}
+
+static void qmp_output_start_list(Visitor *v, const char *name, Error **errp)
+{
+ QmpOutputVisitor *qov = to_qov(v);
+ QList *list = qlist_new();
+
+ qmp_output_add(qov, name, list);
+ qmp_output_push(qov, list);
+}
+
+static GenericList *qmp_output_next_list(Visitor *v, GenericList **list, Error **errp)
+{
+ GenericList *retval = *list;
+ *list = retval->next;
+ return retval;
+}
+
+static void qmp_output_end_list(Visitor *v, Error **errp)
+{
+ QmpOutputVisitor *qov = to_qov(v);
+ qmp_output_pop(qov);
+}
+
+static void qmp_output_type_int(Visitor *v, int64_t *obj, const char *name, Error **errp)
+{
+ QmpOutputVisitor *qov = to_qov(v);
+ qmp_output_add(qov, name, qint_from_int(*obj));
+}
+
+static void qmp_output_type_bool(Visitor *v, bool *obj, const char *name, Error **errp)
+{
+ QmpOutputVisitor *qov = to_qov(v);
+ qmp_output_add(qov, name, qbool_from_int(*obj));
+}
+
+static void qmp_output_type_str(Visitor *v, char **obj, const char *name, Error **errp)
+{
+ QmpOutputVisitor *qov = to_qov(v);
+ qmp_output_add(qov, name, qstring_from_str(*obj));
+}
+
+static void qmp_output_type_number(Visitor *v, double *obj, const char *name, Error **errp)
+{
+ QmpOutputVisitor *qov = to_qov(v);
+ qmp_output_add(qov, name, qfloat_from_double(*obj));
+}
+
+static void qmp_output_type_enum(Visitor *v, int *obj, const char *kind, const char *name, Error **errp)
+{
+ int64_t value = *obj;
+ qmp_output_type_int(v, &value, name, errp);
+}
+
+QObject *qmp_output_get_qobject(QmpOutputVisitor *qov)
+{
+ QObject *obj = qmp_output_first(qov);
+ if (obj) {
+ qobject_incref(obj);
+ }
+ return obj;
+}
+
+Visitor *qmp_output_get_visitor(QmpOutputVisitor *v)
+{
+ return &v->visitor;
+}
+
+void qmp_output_visitor_cleanup(QmpOutputVisitor *v)
+{
+ QStackEntry *e, *tmp;
+
+ QTAILQ_FOREACH_SAFE(e, &v->stack, node, tmp) {
+ QTAILQ_REMOVE(&v->stack, e, node);
+ if (e->value) {
+ qobject_decref(e->value);
+ }
+ qemu_free(e);
+ }
+
+ qemu_free(v);
+}
+
+QmpOutputVisitor *qmp_output_visitor_new(void)
+{
+ QmpOutputVisitor *v;
+
+ v = qemu_mallocz(sizeof(*v));
+
+ v->visitor.start_struct = qmp_output_start_struct;
+ v->visitor.end_struct = qmp_output_end_struct;
+ v->visitor.start_list = qmp_output_start_list;
+ v->visitor.next_list = qmp_output_next_list;
+ v->visitor.end_list = qmp_output_end_list;
+ v->visitor.type_enum = qmp_output_type_enum;
+ v->visitor.type_int = qmp_output_type_int;
+ v->visitor.type_bool = qmp_output_type_bool;
+ v->visitor.type_str = qmp_output_type_str;
+ v->visitor.type_number = qmp_output_type_number;
+
+ QTAILQ_INIT(&v->stack);
+
+ return v;
+}
diff --git a/qapi/qmp-output-visitor.h b/qapi/qmp-output-visitor.h
new file mode 100644
index 0000000..4a649c2
--- /dev/null
+++ b/qapi/qmp-output-visitor.h
@@ -0,0 +1,28 @@
+/*
+ * Output Visitor
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#ifndef QMP_OUTPUT_VISITOR_H
+#define QMP_OUTPUT_VISITOR_H
+
+#include "qapi-visit-core.h"
+#include "qobject.h"
+
+typedef struct QmpOutputVisitor QmpOutputVisitor;
+
+QmpOutputVisitor *qmp_output_visitor_new(void);
+void qmp_output_visitor_cleanup(QmpOutputVisitor *v);
+
+QObject *qmp_output_get_qobject(QmpOutputVisitor *v);
+Visitor *qmp_output_get_visitor(QmpOutputVisitor *v);
+
+#endif
--
1.7.0.4
^ permalink raw reply related [flat|nested] 37+ messages in thread
* [Qemu-devel] [PATCH v3 07/21] qapi: add QAPI dealloc visitor
2011-06-14 2:31 [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v3 Michael Roth
` (5 preceding siblings ...)
2011-06-14 2:31 ` [Qemu-devel] [PATCH v3 06/21] qapi: add QMP output visitor Michael Roth
@ 2011-06-14 2:31 ` Michael Roth
2011-06-15 18:25 ` Luiz Capitulino
2011-06-14 2:31 ` [Qemu-devel] [PATCH v3 08/21] qapi: add QMP command registration/lookup functions Michael Roth
` (13 subsequent siblings)
20 siblings, 1 reply; 37+ messages in thread
From: Michael Roth @ 2011-06-14 2:31 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, Jes.Sorensen, agl, mdroth, lcapitulino
Type of Visitor class that can be passed into a qapi-generated C
type's visitor function to free() any heap-allocated data types.
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
Makefile.objs | 2 +-
qapi/qapi-dealloc-visitor.c | 127 +++++++++++++++++++++++++++++++++++++++++++
qapi/qapi-dealloc-visitor.h | 26 +++++++++
3 files changed, 154 insertions(+), 1 deletions(-)
create mode 100644 qapi/qapi-dealloc-visitor.c
create mode 100644 qapi/qapi-dealloc-visitor.h
diff --git a/Makefile.objs b/Makefile.objs
index af302ea..3860252 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -367,7 +367,7 @@ libcacard-y = cac.o event.o vcard.o vreader.o vcard_emul_nss.o vcard_emul_type.o
######################################################################
# qapi
-qapi-nested-y = qapi-visit-core.o qmp-input-visitor.o qmp-output-visitor.o
+qapi-nested-y = qapi-visit-core.o qmp-input-visitor.o qmp-output-visitor.o qapi-dealloc-visitor.o
qapi-obj-y = $(addprefix qapi/, $(qapi-nested-y))
vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
diff --git a/qapi/qapi-dealloc-visitor.c b/qapi/qapi-dealloc-visitor.c
new file mode 100644
index 0000000..1fabfe6
--- /dev/null
+++ b/qapi/qapi-dealloc-visitor.c
@@ -0,0 +1,127 @@
+#include "qapi-dealloc-visitor.h"
+#include "qemu-queue.h"
+#include "qemu-common.h"
+#include "qemu-objects.h"
+
+typedef struct StackEntry
+{
+ void *value;
+ QTAILQ_ENTRY(StackEntry) node;
+} StackEntry;
+
+struct QapiDeallocVisitor
+{
+ Visitor visitor;
+ QTAILQ_HEAD(, StackEntry) stack;
+};
+
+static QapiDeallocVisitor *to_qov(Visitor *v)
+{
+ return container_of(v, QapiDeallocVisitor, visitor);
+}
+
+static void qapi_dealloc_push(QapiDeallocVisitor *qov, void *value)
+{
+ StackEntry *e = qemu_mallocz(sizeof(*e));
+
+ e->value = value;
+ QTAILQ_INSERT_HEAD(&qov->stack, e, node);
+}
+
+static void *qapi_dealloc_pop(QapiDeallocVisitor *qov)
+{
+ StackEntry *e = QTAILQ_FIRST(&qov->stack);
+ QObject *value;
+ QTAILQ_REMOVE(&qov->stack, e, node);
+ value = e->value;
+ qemu_free(e);
+ return value;
+}
+
+static void qapi_dealloc_start_struct(Visitor *v, void **obj, const char *kind, const char *name, size_t unused, Error **errp)
+{
+ QapiDeallocVisitor *qov = to_qov(v);
+ qapi_dealloc_push(qov, obj);
+}
+
+static void qapi_dealloc_end_struct(Visitor *v, Error **errp)
+{
+ QapiDeallocVisitor *qov = to_qov(v);
+ void **obj = qapi_dealloc_pop(qov);
+ if (obj && *obj) {
+ qemu_free(*obj);
+ }
+}
+
+static void qapi_dealloc_start_list(Visitor *v, const char *name, Error **errp)
+{
+}
+
+static GenericList *qapi_dealloc_next_list(Visitor *v, GenericList **list, Error **errp)
+{
+ GenericList *retval = *list;
+ if (retval->value) {
+ qemu_free(retval->value);
+ }
+ *list = retval->next;
+ return retval;
+}
+
+static void qapi_dealloc_end_list(Visitor *v, Error **errp)
+{
+}
+
+static void qapi_dealloc_type_str(Visitor *v, char **obj, const char *name, Error **errp)
+{
+ if (obj && *obj) {
+ qemu_free(*obj);
+ }
+}
+
+static void qapi_dealloc_type_int(Visitor *v, int64_t *obj, const char *name, Error **errp)
+{
+}
+
+static void qapi_dealloc_type_bool(Visitor *v, bool *obj, const char *name, Error **errp)
+{
+}
+
+static void qapi_dealloc_type_number(Visitor *v, double *obj, const char *name, Error **errp)
+{
+}
+
+static void qapi_dealloc_type_enum(Visitor *v, int *obj, const char *kind, const char *name, Error **errp)
+{
+}
+
+Visitor *qapi_dealloc_get_visitor(QapiDeallocVisitor *v)
+{
+ return &v->visitor;
+}
+
+void qapi_dealloc_visitor_cleanup(QapiDeallocVisitor *v)
+{
+ qemu_free(v);
+}
+
+QapiDeallocVisitor *qapi_dealloc_visitor_new(void)
+{
+ QapiDeallocVisitor *v;
+
+ v = qemu_mallocz(sizeof(*v));
+
+ v->visitor.start_struct = qapi_dealloc_start_struct;
+ v->visitor.end_struct = qapi_dealloc_end_struct;
+ v->visitor.start_list = qapi_dealloc_start_list;
+ v->visitor.next_list = qapi_dealloc_next_list;
+ v->visitor.end_list = qapi_dealloc_end_list;
+ v->visitor.type_enum = qapi_dealloc_type_enum;
+ v->visitor.type_int = qapi_dealloc_type_int;
+ v->visitor.type_bool = qapi_dealloc_type_bool;
+ v->visitor.type_str = qapi_dealloc_type_str;
+ v->visitor.type_number = qapi_dealloc_type_number;
+
+ QTAILQ_INIT(&v->stack);
+
+ return v;
+}
diff --git a/qapi/qapi-dealloc-visitor.h b/qapi/qapi-dealloc-visitor.h
new file mode 100644
index 0000000..5842bc7
--- /dev/null
+++ b/qapi/qapi-dealloc-visitor.h
@@ -0,0 +1,26 @@
+/*
+ * Dealloc Visitor
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ * Michael Roth <mdroth@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#ifndef QAPI_DEALLOC_VISITOR_H
+#define QAPI_DEALLOC_VISITOR_H
+
+#include "qapi-visit-core.h"
+
+typedef struct QapiDeallocVisitor QapiDeallocVisitor;
+
+QapiDeallocVisitor *qapi_dealloc_visitor_new(void);
+void qapi_dealloc_visitor_cleanup(QapiDeallocVisitor *d);
+
+Visitor *qapi_dealloc_get_visitor(QapiDeallocVisitor *v);
+
+#endif
--
1.7.0.4
^ permalink raw reply related [flat|nested] 37+ messages in thread
* Re: [Qemu-devel] [PATCH v3 07/21] qapi: add QAPI dealloc visitor
2011-06-14 2:31 ` [Qemu-devel] [PATCH v3 07/21] qapi: add QAPI dealloc visitor Michael Roth
@ 2011-06-15 18:25 ` Luiz Capitulino
0 siblings, 0 replies; 37+ messages in thread
From: Luiz Capitulino @ 2011-06-15 18:25 UTC (permalink / raw)
To: Michael Roth; +Cc: aliguori, agl, qemu-devel, Jes.Sorensen
On Mon, 13 Jun 2011 21:31:12 -0500
Michael Roth <mdroth@linux.vnet.ibm.com> wrote:
> Type of Visitor class that can be passed into a qapi-generated C
> type's visitor function to free() any heap-allocated data types.
>
> Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
> ---
> Makefile.objs | 2 +-
> qapi/qapi-dealloc-visitor.c | 127 +++++++++++++++++++++++++++++++++++++++++++
> qapi/qapi-dealloc-visitor.h | 26 +++++++++
> 3 files changed, 154 insertions(+), 1 deletions(-)
> create mode 100644 qapi/qapi-dealloc-visitor.c
> create mode 100644 qapi/qapi-dealloc-visitor.h
>
> diff --git a/Makefile.objs b/Makefile.objs
> index af302ea..3860252 100644
> --- a/Makefile.objs
> +++ b/Makefile.objs
> @@ -367,7 +367,7 @@ libcacard-y = cac.o event.o vcard.o vreader.o vcard_emul_nss.o vcard_emul_type.o
> ######################################################################
> # qapi
>
> -qapi-nested-y = qapi-visit-core.o qmp-input-visitor.o qmp-output-visitor.o
> +qapi-nested-y = qapi-visit-core.o qmp-input-visitor.o qmp-output-visitor.o qapi-dealloc-visitor.o
> qapi-obj-y = $(addprefix qapi/, $(qapi-nested-y))
>
> vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
> diff --git a/qapi/qapi-dealloc-visitor.c b/qapi/qapi-dealloc-visitor.c
> new file mode 100644
> index 0000000..1fabfe6
> --- /dev/null
> +++ b/qapi/qapi-dealloc-visitor.c
> @@ -0,0 +1,127 @@
> +#include "qapi-dealloc-visitor.h"
> +#include "qemu-queue.h"
> +#include "qemu-common.h"
> +#include "qemu-objects.h"
> +
> +typedef struct StackEntry
> +{
> + void *value;
> + QTAILQ_ENTRY(StackEntry) node;
> +} StackEntry;
> +
> +struct QapiDeallocVisitor
> +{
> + Visitor visitor;
> + QTAILQ_HEAD(, StackEntry) stack;
> +};
> +
> +static QapiDeallocVisitor *to_qov(Visitor *v)
> +{
> + return container_of(v, QapiDeallocVisitor, visitor);
> +}
> +
> +static void qapi_dealloc_push(QapiDeallocVisitor *qov, void *value)
> +{
> + StackEntry *e = qemu_mallocz(sizeof(*e));
> +
> + e->value = value;
> + QTAILQ_INSERT_HEAD(&qov->stack, e, node);
> +}
> +
> +static void *qapi_dealloc_pop(QapiDeallocVisitor *qov)
> +{
> + StackEntry *e = QTAILQ_FIRST(&qov->stack);
> + QObject *value;
> + QTAILQ_REMOVE(&qov->stack, e, node);
> + value = e->value;
> + qemu_free(e);
> + return value;
> +}
> +
> +static void qapi_dealloc_start_struct(Visitor *v, void **obj, const char *kind, const char *name, size_t unused, Error **errp)
> +{
> + QapiDeallocVisitor *qov = to_qov(v);
> + qapi_dealloc_push(qov, obj);
> +}
> +
> +static void qapi_dealloc_end_struct(Visitor *v, Error **errp)
> +{
> + QapiDeallocVisitor *qov = to_qov(v);
> + void **obj = qapi_dealloc_pop(qov);
> + if (obj && *obj) {
> + qemu_free(*obj);
> + }
> +}
> +
> +static void qapi_dealloc_start_list(Visitor *v, const char *name, Error **errp)
> +{
> +}
> +
> +static GenericList *qapi_dealloc_next_list(Visitor *v, GenericList **list, Error **errp)
> +{
> + GenericList *retval = *list;
> + if (retval->value) {
> + qemu_free(retval->value);
> + }
> + *list = retval->next;
> + return retval;
> +}
> +
> +static void qapi_dealloc_end_list(Visitor *v, Error **errp)
> +{
> +}
> +
> +static void qapi_dealloc_type_str(Visitor *v, char **obj, const char *name, Error **errp)
> +{
> + if (obj && *obj) {
> + qemu_free(*obj);
> + }
qemu_free() knows how to deal with nulls. This applies to the three
qemu_free() calls in above.
> +}
> +
> +static void qapi_dealloc_type_int(Visitor *v, int64_t *obj, const char *name, Error **errp)
> +{
> +}
> +
> +static void qapi_dealloc_type_bool(Visitor *v, bool *obj, const char *name, Error **errp)
> +{
> +}
> +
> +static void qapi_dealloc_type_number(Visitor *v, double *obj, const char *name, Error **errp)
> +{
> +}
> +
> +static void qapi_dealloc_type_enum(Visitor *v, int *obj, const char *kind, const char *name, Error **errp)
> +{
> +}
> +
> +Visitor *qapi_dealloc_get_visitor(QapiDeallocVisitor *v)
> +{
> + return &v->visitor;
> +}
> +
> +void qapi_dealloc_visitor_cleanup(QapiDeallocVisitor *v)
> +{
> + qemu_free(v);
> +}
> +
> +QapiDeallocVisitor *qapi_dealloc_visitor_new(void)
> +{
> + QapiDeallocVisitor *v;
> +
> + v = qemu_mallocz(sizeof(*v));
> +
> + v->visitor.start_struct = qapi_dealloc_start_struct;
> + v->visitor.end_struct = qapi_dealloc_end_struct;
> + v->visitor.start_list = qapi_dealloc_start_list;
> + v->visitor.next_list = qapi_dealloc_next_list;
> + v->visitor.end_list = qapi_dealloc_end_list;
> + v->visitor.type_enum = qapi_dealloc_type_enum;
> + v->visitor.type_int = qapi_dealloc_type_int;
> + v->visitor.type_bool = qapi_dealloc_type_bool;
> + v->visitor.type_str = qapi_dealloc_type_str;
> + v->visitor.type_number = qapi_dealloc_type_number;
> +
> + QTAILQ_INIT(&v->stack);
> +
> + return v;
> +}
> diff --git a/qapi/qapi-dealloc-visitor.h b/qapi/qapi-dealloc-visitor.h
> new file mode 100644
> index 0000000..5842bc7
> --- /dev/null
> +++ b/qapi/qapi-dealloc-visitor.h
> @@ -0,0 +1,26 @@
> +/*
> + * Dealloc Visitor
> + *
> + * Copyright IBM, Corp. 2011
> + *
> + * Authors:
> + * Michael Roth <mdroth@linux.vnet.ibm.com>
> + *
> + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
> + * See the COPYING.LIB file in the top-level directory.
> + *
> + */
> +
> +#ifndef QAPI_DEALLOC_VISITOR_H
> +#define QAPI_DEALLOC_VISITOR_H
> +
> +#include "qapi-visit-core.h"
> +
> +typedef struct QapiDeallocVisitor QapiDeallocVisitor;
> +
> +QapiDeallocVisitor *qapi_dealloc_visitor_new(void);
> +void qapi_dealloc_visitor_cleanup(QapiDeallocVisitor *d);
> +
> +Visitor *qapi_dealloc_get_visitor(QapiDeallocVisitor *v);
> +
> +#endif
^ permalink raw reply [flat|nested] 37+ messages in thread
* [Qemu-devel] [PATCH v3 08/21] qapi: add QMP command registration/lookup functions
2011-06-14 2:31 [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v3 Michael Roth
` (6 preceding siblings ...)
2011-06-14 2:31 ` [Qemu-devel] [PATCH v3 07/21] qapi: add QAPI dealloc visitor Michael Roth
@ 2011-06-14 2:31 ` Michael Roth
2011-06-14 2:31 ` [Qemu-devel] [PATCH v3 09/21] qapi: add QMP dispatch functions Michael Roth
` (12 subsequent siblings)
20 siblings, 0 replies; 37+ messages in thread
From: Michael Roth @ 2011-06-14 2:31 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, Jes.Sorensen, agl, mdroth, lcapitulino
Registration/lookup functions for that provide a lookup table for
dispatching QMP commands.
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
Makefile.objs | 1 +
qapi/qmp-core.h | 40 ++++++++++++++++++++++++++++++++++++++++
qapi/qmp-registry.c | 26 ++++++++++++++++++++++++++
3 files changed, 67 insertions(+), 0 deletions(-)
create mode 100644 qapi/qmp-core.h
create mode 100644 qapi/qmp-registry.c
diff --git a/Makefile.objs b/Makefile.objs
index 3860252..092f314 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -368,6 +368,7 @@ libcacard-y = cac.o event.o vcard.o vreader.o vcard_emul_nss.o vcard_emul_type.o
# qapi
qapi-nested-y = qapi-visit-core.o qmp-input-visitor.o qmp-output-visitor.o qapi-dealloc-visitor.o
+qapi-nested-y += qmp-registry.o
qapi-obj-y = $(addprefix qapi/, $(qapi-nested-y))
vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
diff --git a/qapi/qmp-core.h b/qapi/qmp-core.h
new file mode 100644
index 0000000..99e929f
--- /dev/null
+++ b/qapi/qmp-core.h
@@ -0,0 +1,40 @@
+/*
+ * Core Definitions for QAPI/QMP Dispatch
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#ifndef QMP_CORE_H
+#define QMP_CORE_H
+
+#include "qobject.h"
+#include "qdict.h"
+#include "error.h"
+
+typedef void (QmpCommandFunc)(QDict *, QObject **, Error **);
+
+typedef enum QmpCommandType
+{
+ QCT_NORMAL,
+} QmpCommandType;
+
+typedef struct QmpCommand
+{
+ const char *name;
+ QmpCommandType type;
+ QmpCommandFunc *fn;
+ QTAILQ_ENTRY(QmpCommand) node;
+} QmpCommand;
+
+void qmp_register_command(const char *name, QmpCommandFunc *fn);
+QmpCommand *qmp_find_command(const char *name);
+
+#endif
+
diff --git a/qapi/qmp-registry.c b/qapi/qmp-registry.c
new file mode 100644
index 0000000..d3ff8b3
--- /dev/null
+++ b/qapi/qmp-registry.c
@@ -0,0 +1,26 @@
+#include "qapi/qmp-core.h"
+
+static QTAILQ_HEAD(, QmpCommand) qmp_commands =
+ QTAILQ_HEAD_INITIALIZER(qmp_commands);
+
+void qmp_register_command(const char *name, QmpCommandFunc *fn)
+{
+ QmpCommand *cmd = qemu_mallocz(sizeof(*cmd));
+
+ cmd->name = name;
+ cmd->type = QCT_NORMAL;
+ cmd->fn = fn;
+ QTAILQ_INSERT_TAIL(&qmp_commands, cmd, node);
+}
+
+QmpCommand *qmp_find_command(const char *name)
+{
+ QmpCommand *i;
+
+ QTAILQ_FOREACH(i, &qmp_commands, node) {
+ if (strcmp(i->name, name) == 0) {
+ return i;
+ }
+ }
+ return NULL;
+}
--
1.7.0.4
^ permalink raw reply related [flat|nested] 37+ messages in thread
* [Qemu-devel] [PATCH v3 09/21] qapi: add QMP dispatch functions
2011-06-14 2:31 [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v3 Michael Roth
` (7 preceding siblings ...)
2011-06-14 2:31 ` [Qemu-devel] [PATCH v3 08/21] qapi: add QMP command registration/lookup functions Michael Roth
@ 2011-06-14 2:31 ` Michael Roth
2011-06-15 19:33 ` Luiz Capitulino
2011-06-14 2:31 ` [Qemu-devel] [PATCH v3 10/21] qapi: add ordereddict.py helper library Michael Roth
` (11 subsequent siblings)
20 siblings, 1 reply; 37+ messages in thread
From: Michael Roth @ 2011-06-14 2:31 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, Jes.Sorensen, agl, mdroth, lcapitulino
Given an object recieved via QMP, this code uses the dispatch table
provided by qmp_registry.c to call the corresponding marshalling/dispatch
function and format return values/errors for delivery to the QMP.
Currently only synchronous QMP functions are supported, but this will
also be used for async QMP functions and QMP guest proxy dispatch as
well.
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
Makefile.objs | 2 +-
qapi/qmp-core.h | 1 +
qapi/qmp-dispatch.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 78 insertions(+), 1 deletions(-)
create mode 100644 qapi/qmp-dispatch.c
diff --git a/Makefile.objs b/Makefile.objs
index 092f314..7e82587 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -368,7 +368,7 @@ libcacard-y = cac.o event.o vcard.o vreader.o vcard_emul_nss.o vcard_emul_type.o
# qapi
qapi-nested-y = qapi-visit-core.o qmp-input-visitor.o qmp-output-visitor.o qapi-dealloc-visitor.o
-qapi-nested-y += qmp-registry.o
+qapi-nested-y += qmp-registry.o qmp-dispatch.o
qapi-obj-y = $(addprefix qapi/, $(qapi-nested-y))
vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
diff --git a/qapi/qmp-core.h b/qapi/qmp-core.h
index 99e929f..f1c26e4 100644
--- a/qapi/qmp-core.h
+++ b/qapi/qmp-core.h
@@ -35,6 +35,7 @@ typedef struct QmpCommand
void qmp_register_command(const char *name, QmpCommandFunc *fn);
QmpCommand *qmp_find_command(const char *name);
+QObject *qmp_dispatch(QObject *request);
#endif
diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c
new file mode 100644
index 0000000..5bf41ea
--- /dev/null
+++ b/qapi/qmp-dispatch.c
@@ -0,0 +1,76 @@
+#include "qemu-objects.h"
+#include "qapi/qmp-core.h"
+#include "json-parser.h"
+#include "error.h"
+#include "error_int.h"
+#include "qerror.h"
+
+static QObject *qmp_dispatch_err(QObject *request, Error **errp)
+{
+ const char *command;
+ QDict *args, *dict;
+ QmpCommand *cmd;
+ QObject *ret = NULL;
+
+ if (qobject_type(request) != QTYPE_QDICT) {
+ error_set(errp, QERR_JSON_PARSE_ERROR, "request is not a dictionary");
+ goto out;
+ }
+
+ dict = qobject_to_qdict(request);
+ if (!qdict_haskey(dict, "execute")) {
+ error_set(errp, QERR_JSON_PARSE_ERROR, "no execute key");
+ goto out;
+ }
+
+ command = qdict_get_str(dict, "execute");
+ cmd = qmp_find_command(command);
+ if (cmd == NULL) {
+ error_set(errp, QERR_COMMAND_NOT_FOUND, command);
+ goto out;
+ }
+
+ if (!qdict_haskey(dict, "arguments")) {
+ args = qdict_new();
+ } else {
+ args = qdict_get_qdict(dict, "arguments");
+ QINCREF(args);
+ }
+
+ switch (cmd->type) {
+ case QCT_NORMAL:
+ cmd->fn(args, &ret, errp);
+ if (!error_is_set(errp) && ret == NULL) {
+ ret = QOBJECT(qdict_new());
+ }
+ break;
+ }
+
+ QDECREF(args);
+
+out:
+
+ return ret;
+}
+
+QObject *qmp_dispatch(QObject *request)
+{
+ Error *err = NULL;
+ QObject *ret;
+ QDict *rsp;
+
+ ret = qmp_dispatch_err(request, &err);
+
+ rsp = qdict_new();
+ if (err) {
+ qdict_put_obj(rsp, "error", error_get_qobject(err));
+ error_free(err);
+ } else if (ret) {
+ qdict_put_obj(rsp, "return", ret);
+ } else {
+ QDECREF(rsp);
+ return NULL;
+ }
+
+ return QOBJECT(rsp);
+}
--
1.7.0.4
^ permalink raw reply related [flat|nested] 37+ messages in thread
* Re: [Qemu-devel] [PATCH v3 09/21] qapi: add QMP dispatch functions
2011-06-14 2:31 ` [Qemu-devel] [PATCH v3 09/21] qapi: add QMP dispatch functions Michael Roth
@ 2011-06-15 19:33 ` Luiz Capitulino
2011-06-15 19:45 ` Anthony Liguori
0 siblings, 1 reply; 37+ messages in thread
From: Luiz Capitulino @ 2011-06-15 19:33 UTC (permalink / raw)
To: Michael Roth; +Cc: aliguori, agl, qemu-devel, Jes.Sorensen
On Mon, 13 Jun 2011 21:31:14 -0500
Michael Roth <mdroth@linux.vnet.ibm.com> wrote:
> Given an object recieved via QMP, this code uses the dispatch table
> provided by qmp_registry.c to call the corresponding marshalling/dispatch
> function and format return values/errors for delivery to the QMP.
> Currently only synchronous QMP functions are supported, but this will
> also be used for async QMP functions and QMP guest proxy dispatch as
> well.
>
> Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
> ---
> Makefile.objs | 2 +-
> qapi/qmp-core.h | 1 +
> qapi/qmp-dispatch.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 78 insertions(+), 1 deletions(-)
> create mode 100644 qapi/qmp-dispatch.c
>
> diff --git a/Makefile.objs b/Makefile.objs
> index 092f314..7e82587 100644
> --- a/Makefile.objs
> +++ b/Makefile.objs
> @@ -368,7 +368,7 @@ libcacard-y = cac.o event.o vcard.o vreader.o vcard_emul_nss.o vcard_emul_type.o
> # qapi
>
> qapi-nested-y = qapi-visit-core.o qmp-input-visitor.o qmp-output-visitor.o qapi-dealloc-visitor.o
> -qapi-nested-y += qmp-registry.o
> +qapi-nested-y += qmp-registry.o qmp-dispatch.o
> qapi-obj-y = $(addprefix qapi/, $(qapi-nested-y))
>
> vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
> diff --git a/qapi/qmp-core.h b/qapi/qmp-core.h
> index 99e929f..f1c26e4 100644
> --- a/qapi/qmp-core.h
> +++ b/qapi/qmp-core.h
> @@ -35,6 +35,7 @@ typedef struct QmpCommand
>
> void qmp_register_command(const char *name, QmpCommandFunc *fn);
> QmpCommand *qmp_find_command(const char *name);
> +QObject *qmp_dispatch(QObject *request);
>
> #endif
>
> diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c
> new file mode 100644
> index 0000000..5bf41ea
> --- /dev/null
> +++ b/qapi/qmp-dispatch.c
> @@ -0,0 +1,76 @@
> +#include "qemu-objects.h"
> +#include "qapi/qmp-core.h"
> +#include "json-parser.h"
> +#include "error.h"
> +#include "error_int.h"
> +#include "qerror.h"
> +
> +static QObject *qmp_dispatch_err(QObject *request, Error **errp)
Please, call this do_qmp_dispatch() instead. Every time I turn to this
function I tend to think this is only called when dispatch fails :)
> +{
> + const char *command;
> + QDict *args, *dict;
> + QmpCommand *cmd;
> + QObject *ret = NULL;
> +
> + if (qobject_type(request) != QTYPE_QDICT) {
> + error_set(errp, QERR_JSON_PARSE_ERROR, "request is not a dictionary");
> + goto out;
> + }
> +
> + dict = qobject_to_qdict(request);
> + if (!qdict_haskey(dict, "execute")) {
> + error_set(errp, QERR_JSON_PARSE_ERROR, "no execute key");
> + goto out;
> + }
> +
> + command = qdict_get_str(dict, "execute");
> + cmd = qmp_find_command(command);
> + if (cmd == NULL) {
> + error_set(errp, QERR_COMMAND_NOT_FOUND, command);
> + goto out;
> + }
> +
> + if (!qdict_haskey(dict, "arguments")) {
> + args = qdict_new();
> + } else {
> + args = qdict_get_qdict(dict, "arguments");
> + QINCREF(args);
> + }
This function doesn't seem to handle extra keys in the command dict, like:
{ "execute": "query-block", "foo": "bar" }
You probably want to use qmp_check_input_obj() here.
> +
> + switch (cmd->type) {
> + case QCT_NORMAL:
> + cmd->fn(args, &ret, errp);
> + if (!error_is_set(errp) && ret == NULL) {
> + ret = QOBJECT(qdict_new());
> + }
> + break;
> + }
> +
> + QDECREF(args);
> +
> +out:
> +
> + return ret;
> +}
> +
> +QObject *qmp_dispatch(QObject *request)
> +{
> + Error *err = NULL;
> + QObject *ret;
> + QDict *rsp;
> +
> + ret = qmp_dispatch_err(request, &err);
> +
> + rsp = qdict_new();
> + if (err) {
> + qdict_put_obj(rsp, "error", error_get_qobject(err));
> + error_free(err);
> + } else if (ret) {
> + qdict_put_obj(rsp, "return", ret);
> + } else {
> + QDECREF(rsp);
> + return NULL;
When does the 'else' condition happens?
> + }
> +
> + return QOBJECT(rsp);
> +}
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [Qemu-devel] [PATCH v3 09/21] qapi: add QMP dispatch functions
2011-06-15 19:33 ` Luiz Capitulino
@ 2011-06-15 19:45 ` Anthony Liguori
2011-06-15 20:12 ` Luiz Capitulino
0 siblings, 1 reply; 37+ messages in thread
From: Anthony Liguori @ 2011-06-15 19:45 UTC (permalink / raw)
To: Luiz Capitulino; +Cc: Jes.Sorensen, agl, Michael Roth, qemu-devel
On 06/15/2011 02:33 PM, Luiz Capitulino wrote:
> On Mon, 13 Jun 2011 21:31:14 -0500
> Michael Roth<mdroth@linux.vnet.ibm.com> wrote:
>
>
>> +{
>> + const char *command;
>> + QDict *args, *dict;
>> + QmpCommand *cmd;
>> + QObject *ret = NULL;
>> +
>> + if (qobject_type(request) != QTYPE_QDICT) {
>> + error_set(errp, QERR_JSON_PARSE_ERROR, "request is not a dictionary");
>> + goto out;
>> + }
>> +
>> + dict = qobject_to_qdict(request);
>> + if (!qdict_haskey(dict, "execute")) {
>> + error_set(errp, QERR_JSON_PARSE_ERROR, "no execute key");
>> + goto out;
>> + }
>> +
>> + command = qdict_get_str(dict, "execute");
>> + cmd = qmp_find_command(command);
>> + if (cmd == NULL) {
>> + error_set(errp, QERR_COMMAND_NOT_FOUND, command);
>> + goto out;
>> + }
>> +
>> + if (!qdict_haskey(dict, "arguments")) {
>> + args = qdict_new();
>> + } else {
>> + args = qdict_get_qdict(dict, "arguments");
>> + QINCREF(args);
>> + }
>
> This function doesn't seem to handle extra keys in the command dict, like:
>
> { "execute": "query-block", "foo": "bar" }
>
> You probably want to use qmp_check_input_obj() here.
That's a feature, no?
"Be liberal in what you accept, conservative in what you send."
>
>> +
>> + switch (cmd->type) {
>> + case QCT_NORMAL:
>> + cmd->fn(args,&ret, errp);
>> + if (!error_is_set(errp)&& ret == NULL) {
>> + ret = QOBJECT(qdict_new());
>> + }
>> + break;
>> + }
>> +
>> + QDECREF(args);
>> +
>> +out:
>> +
>> + return ret;
>> +}
>> +
>> +QObject *qmp_dispatch(QObject *request)
>> +{
>> + Error *err = NULL;
>> + QObject *ret;
>> + QDict *rsp;
>> +
>> + ret = qmp_dispatch_err(request,&err);
>> +
>> + rsp = qdict_new();
>> + if (err) {
>> + qdict_put_obj(rsp, "error", error_get_qobject(err));
>> + error_free(err);
>> + } else if (ret) {
>> + qdict_put_obj(rsp, "return", ret);
>> + } else {
>> + QDECREF(rsp);
>> + return NULL;
>
> When does the 'else' condition happens?
Signals which aren't in this patch series.
Regards,
Anthony Liguori
>
>> + }
>> +
>> + return QOBJECT(rsp);
>> +}
>
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [Qemu-devel] [PATCH v3 09/21] qapi: add QMP dispatch functions
2011-06-15 19:45 ` Anthony Liguori
@ 2011-06-15 20:12 ` Luiz Capitulino
2011-06-15 20:45 ` Michael Roth
0 siblings, 1 reply; 37+ messages in thread
From: Luiz Capitulino @ 2011-06-15 20:12 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Jes.Sorensen, agl, Michael Roth, qemu-devel
On Wed, 15 Jun 2011 14:45:30 -0500
Anthony Liguori <aliguori@us.ibm.com> wrote:
> On 06/15/2011 02:33 PM, Luiz Capitulino wrote:
> > On Mon, 13 Jun 2011 21:31:14 -0500
> > Michael Roth<mdroth@linux.vnet.ibm.com> wrote:
> >
> >
> >> +{
> >> + const char *command;
> >> + QDict *args, *dict;
> >> + QmpCommand *cmd;
> >> + QObject *ret = NULL;
> >> +
> >> + if (qobject_type(request) != QTYPE_QDICT) {
> >> + error_set(errp, QERR_JSON_PARSE_ERROR, "request is not a dictionary");
> >> + goto out;
> >> + }
> >> +
> >> + dict = qobject_to_qdict(request);
> >> + if (!qdict_haskey(dict, "execute")) {
> >> + error_set(errp, QERR_JSON_PARSE_ERROR, "no execute key");
> >> + goto out;
> >> + }
> >> +
> >> + command = qdict_get_str(dict, "execute");
> >> + cmd = qmp_find_command(command);
> >> + if (cmd == NULL) {
> >> + error_set(errp, QERR_COMMAND_NOT_FOUND, command);
> >> + goto out;
> >> + }
> >> +
> >> + if (!qdict_haskey(dict, "arguments")) {
> >> + args = qdict_new();
> >> + } else {
> >> + args = qdict_get_qdict(dict, "arguments");
> >> + QINCREF(args);
> >> + }
> >
> > This function doesn't seem to handle extra keys in the command dict, like:
> >
> > { "execute": "query-block", "foo": "bar" }
> >
> > You probably want to use qmp_check_input_obj() here.
>
> That's a feature, no?
>
> "Be liberal in what you accept, conservative in what you send."
I'm not sure the principle applies in this case, as this is an invalid
argument. This is the kind of thing that could give a hard time to clients,
like using a new argument on an old command and wonder why it doesn't work.
Libvirt did something like this in the past when we weren't doing the check,
they were passing an additional key for some command and expecting it would
have the desired functionality.
> >> +
> >> + switch (cmd->type) {
> >> + case QCT_NORMAL:
> >> + cmd->fn(args,&ret, errp);
> >> + if (!error_is_set(errp)&& ret == NULL) {
> >> + ret = QOBJECT(qdict_new());
> >> + }
> >> + break;
> >> + }
> >> +
> >> + QDECREF(args);
> >> +
> >> +out:
> >> +
> >> + return ret;
> >> +}
> >> +
> >> +QObject *qmp_dispatch(QObject *request)
> >> +{
> >> + Error *err = NULL;
> >> + QObject *ret;
> >> + QDict *rsp;
> >> +
> >> + ret = qmp_dispatch_err(request,&err);
> >> +
> >> + rsp = qdict_new();
> >> + if (err) {
> >> + qdict_put_obj(rsp, "error", error_get_qobject(err));
> >> + error_free(err);
> >> + } else if (ret) {
> >> + qdict_put_obj(rsp, "return", ret);
> >> + } else {
> >> + QDECREF(rsp);
> >> + return NULL;
> >
> > When does the 'else' condition happens?
>
> Signals which aren't in this patch series.
It can be dropped then.
>
> Regards,
>
> Anthony Liguori
>
> >
> >> + }
> >> +
> >> + return QOBJECT(rsp);
> >> +}
> >
>
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [Qemu-devel] [PATCH v3 09/21] qapi: add QMP dispatch functions
2011-06-15 20:12 ` Luiz Capitulino
@ 2011-06-15 20:45 ` Michael Roth
2011-06-15 20:48 ` Luiz Capitulino
0 siblings, 1 reply; 37+ messages in thread
From: Michael Roth @ 2011-06-15 20:45 UTC (permalink / raw)
To: Luiz Capitulino; +Cc: Jes.Sorensen, Anthony Liguori, agl, qemu-devel
On 06/15/2011 03:12 PM, Luiz Capitulino wrote:
> On Wed, 15 Jun 2011 14:45:30 -0500
> Anthony Liguori<aliguori@us.ibm.com> wrote:
>
>> On 06/15/2011 02:33 PM, Luiz Capitulino wrote:
>>> On Mon, 13 Jun 2011 21:31:14 -0500
>>> Michael Roth<mdroth@linux.vnet.ibm.com> wrote:
>>>
>>>
>>>> +{
>>>> + const char *command;
>>>> + QDict *args, *dict;
>>>> + QmpCommand *cmd;
>>>> + QObject *ret = NULL;
>>>> +
>>>> + if (qobject_type(request) != QTYPE_QDICT) {
>>>> + error_set(errp, QERR_JSON_PARSE_ERROR, "request is not a dictionary");
>>>> + goto out;
>>>> + }
>>>> +
>>>> + dict = qobject_to_qdict(request);
>>>> + if (!qdict_haskey(dict, "execute")) {
>>>> + error_set(errp, QERR_JSON_PARSE_ERROR, "no execute key");
>>>> + goto out;
>>>> + }
>>>> +
>>>> + command = qdict_get_str(dict, "execute");
>>>> + cmd = qmp_find_command(command);
>>>> + if (cmd == NULL) {
>>>> + error_set(errp, QERR_COMMAND_NOT_FOUND, command);
>>>> + goto out;
>>>> + }
>>>> +
>>>> + if (!qdict_haskey(dict, "arguments")) {
>>>> + args = qdict_new();
>>>> + } else {
>>>> + args = qdict_get_qdict(dict, "arguments");
>>>> + QINCREF(args);
>>>> + }
>>>
>>> This function doesn't seem to handle extra keys in the command dict, like:
>>>
>>> { "execute": "query-block", "foo": "bar" }
>>>
>>> You probably want to use qmp_check_input_obj() here.
>>
>> That's a feature, no?
>>
>> "Be liberal in what you accept, conservative in what you send."
>
> I'm not sure the principle applies in this case, as this is an invalid
> argument. This is the kind of thing that could give a hard time to clients,
> like using a new argument on an old command and wonder why it doesn't work.
>
> Libvirt did something like this in the past when we weren't doing the check,
> they were passing an additional key for some command and expecting it would
> have the desired functionality.
>
>>>> +
>>>> + switch (cmd->type) {
>>>> + case QCT_NORMAL:
>>>> + cmd->fn(args,&ret, errp);
>>>> + if (!error_is_set(errp)&& ret == NULL) {
>>>> + ret = QOBJECT(qdict_new());
>>>> + }
>>>> + break;
>>>> + }
>>>> +
>>>> + QDECREF(args);
>>>> +
>>>> +out:
>>>> +
>>>> + return ret;
>>>> +}
>>>> +
>>>> +QObject *qmp_dispatch(QObject *request)
>>>> +{
>>>> + Error *err = NULL;
>>>> + QObject *ret;
>>>> + QDict *rsp;
>>>> +
>>>> + ret = qmp_dispatch_err(request,&err);
>>>> +
>>>> + rsp = qdict_new();
>>>> + if (err) {
>>>> + qdict_put_obj(rsp, "error", error_get_qobject(err));
>>>> + error_free(err);
>>>> + } else if (ret) {
>>>> + qdict_put_obj(rsp, "return", ret);
>>>> + } else {
>>>> + QDECREF(rsp);
>>>> + return NULL;
>>>
>>> When does the 'else' condition happens?
>>
>> Signals which aren't in this patch series.
>
> It can be dropped then.
>
I think it's still a good safeguard in the meantime. Whether it's
reachable or not is hard to know without looking over a lot of code
outside the function, and things can change over time. This way the user
can expect a NULL for an undefined error, as opposed to an empty
dictionary they need to free, which isn't very intuitive.
>>
>> Regards,
>>
>> Anthony Liguori
>>
>>>
>>>> + }
>>>> +
>>>> + return QOBJECT(rsp);
>>>> +}
>>>
>>
>
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [Qemu-devel] [PATCH v3 09/21] qapi: add QMP dispatch functions
2011-06-15 20:45 ` Michael Roth
@ 2011-06-15 20:48 ` Luiz Capitulino
0 siblings, 0 replies; 37+ messages in thread
From: Luiz Capitulino @ 2011-06-15 20:48 UTC (permalink / raw)
To: Michael Roth; +Cc: Jes.Sorensen, Anthony Liguori, agl, qemu-devel
On Wed, 15 Jun 2011 15:45:20 -0500
Michael Roth <mdroth@linux.vnet.ibm.com> wrote:
> On 06/15/2011 03:12 PM, Luiz Capitulino wrote:
> > On Wed, 15 Jun 2011 14:45:30 -0500
> > Anthony Liguori<aliguori@us.ibm.com> wrote:
> >
> >> On 06/15/2011 02:33 PM, Luiz Capitulino wrote:
> >>> On Mon, 13 Jun 2011 21:31:14 -0500
> >>> Michael Roth<mdroth@linux.vnet.ibm.com> wrote:
> >>>
> >>>
> >>>> +{
> >>>> + const char *command;
> >>>> + QDict *args, *dict;
> >>>> + QmpCommand *cmd;
> >>>> + QObject *ret = NULL;
> >>>> +
> >>>> + if (qobject_type(request) != QTYPE_QDICT) {
> >>>> + error_set(errp, QERR_JSON_PARSE_ERROR, "request is not a dictionary");
> >>>> + goto out;
> >>>> + }
> >>>> +
> >>>> + dict = qobject_to_qdict(request);
> >>>> + if (!qdict_haskey(dict, "execute")) {
> >>>> + error_set(errp, QERR_JSON_PARSE_ERROR, "no execute key");
> >>>> + goto out;
> >>>> + }
> >>>> +
> >>>> + command = qdict_get_str(dict, "execute");
> >>>> + cmd = qmp_find_command(command);
> >>>> + if (cmd == NULL) {
> >>>> + error_set(errp, QERR_COMMAND_NOT_FOUND, command);
> >>>> + goto out;
> >>>> + }
> >>>> +
> >>>> + if (!qdict_haskey(dict, "arguments")) {
> >>>> + args = qdict_new();
> >>>> + } else {
> >>>> + args = qdict_get_qdict(dict, "arguments");
> >>>> + QINCREF(args);
> >>>> + }
> >>>
> >>> This function doesn't seem to handle extra keys in the command dict, like:
> >>>
> >>> { "execute": "query-block", "foo": "bar" }
> >>>
> >>> You probably want to use qmp_check_input_obj() here.
> >>
> >> That's a feature, no?
> >>
> >> "Be liberal in what you accept, conservative in what you send."
> >
> > I'm not sure the principle applies in this case, as this is an invalid
> > argument. This is the kind of thing that could give a hard time to clients,
> > like using a new argument on an old command and wonder why it doesn't work.
> >
> > Libvirt did something like this in the past when we weren't doing the check,
> > they were passing an additional key for some command and expecting it would
> > have the desired functionality.
> >
> >>>> +
> >>>> + switch (cmd->type) {
> >>>> + case QCT_NORMAL:
> >>>> + cmd->fn(args,&ret, errp);
> >>>> + if (!error_is_set(errp)&& ret == NULL) {
> >>>> + ret = QOBJECT(qdict_new());
> >>>> + }
> >>>> + break;
> >>>> + }
> >>>> +
> >>>> + QDECREF(args);
> >>>> +
> >>>> +out:
> >>>> +
> >>>> + return ret;
> >>>> +}
> >>>> +
> >>>> +QObject *qmp_dispatch(QObject *request)
> >>>> +{
> >>>> + Error *err = NULL;
> >>>> + QObject *ret;
> >>>> + QDict *rsp;
> >>>> +
> >>>> + ret = qmp_dispatch_err(request,&err);
> >>>> +
> >>>> + rsp = qdict_new();
> >>>> + if (err) {
> >>>> + qdict_put_obj(rsp, "error", error_get_qobject(err));
> >>>> + error_free(err);
> >>>> + } else if (ret) {
> >>>> + qdict_put_obj(rsp, "return", ret);
> >>>> + } else {
> >>>> + QDECREF(rsp);
> >>>> + return NULL;
> >>>
> >>> When does the 'else' condition happens?
> >>
> >> Signals which aren't in this patch series.
> >
> > It can be dropped then.
> >
>
> I think it's still a good safeguard in the meantime. Whether it's
> reachable or not is hard to know without looking over a lot of code
> outside the function, and things can change over time. This way the user
> can expect a NULL for an undefined error, as opposed to an empty
> dictionary they need to free, which isn't very intuitive.
Makes sense. Although I think I prefer an assert(). But I'm not strong
about it.
>
> >>
> >> Regards,
> >>
> >> Anthony Liguori
> >>
> >>>
> >>>> + }
> >>>> +
> >>>> + return QOBJECT(rsp);
> >>>> +}
> >>>
> >>
> >
>
^ permalink raw reply [flat|nested] 37+ messages in thread
* [Qemu-devel] [PATCH v3 10/21] qapi: add ordereddict.py helper library
2011-06-14 2:31 [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v3 Michael Roth
` (8 preceding siblings ...)
2011-06-14 2:31 ` [Qemu-devel] [PATCH v3 09/21] qapi: add QMP dispatch functions Michael Roth
@ 2011-06-14 2:31 ` Michael Roth
2011-06-14 2:31 ` [Qemu-devel] [PATCH v3 11/21] qapi: add qapi.py helper libraries Michael Roth
` (10 subsequent siblings)
20 siblings, 0 replies; 37+ messages in thread
From: Michael Roth @ 2011-06-14 2:31 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, Jes.Sorensen, agl, mdroth, lcapitulino
We need this to parse dictionaries with schema ordering intact so that C
prototypes can be generated deterministically.
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
scripts/ordereddict.py | 128 ++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 128 insertions(+), 0 deletions(-)
create mode 100644 scripts/ordereddict.py
diff --git a/scripts/ordereddict.py b/scripts/ordereddict.py
new file mode 100644
index 0000000..e17269f
--- /dev/null
+++ b/scripts/ordereddict.py
@@ -0,0 +1,128 @@
+# Copyright (c) 2009 Raymond Hettinger
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation files
+# (the "Software"), to deal in the Software without restriction,
+# including without limitation the rights to use, copy, modify, merge,
+# publish, distribute, sublicense, and/or sell copies of the Software,
+# and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+# OTHER DEALINGS IN THE SOFTWARE.
+
+from UserDict import DictMixin
+
+class OrderedDict(dict, DictMixin):
+
+ def __init__(self, *args, **kwds):
+ if len(args) > 1:
+ raise TypeError('expected at most 1 arguments, got %d' % len(args))
+ try:
+ self.__end
+ except AttributeError:
+ self.clear()
+ self.update(*args, **kwds)
+
+ def clear(self):
+ self.__end = end = []
+ end += [None, end, end] # sentinel node for doubly linked list
+ self.__map = {} # key --> [key, prev, next]
+ dict.clear(self)
+
+ def __setitem__(self, key, value):
+ if key not in self:
+ end = self.__end
+ curr = end[1]
+ curr[2] = end[1] = self.__map[key] = [key, curr, end]
+ dict.__setitem__(self, key, value)
+
+ def __delitem__(self, key):
+ dict.__delitem__(self, key)
+ key, prev, next = self.__map.pop(key)
+ prev[2] = next
+ next[1] = prev
+
+ def __iter__(self):
+ end = self.__end
+ curr = end[2]
+ while curr is not end:
+ yield curr[0]
+ curr = curr[2]
+
+ def __reversed__(self):
+ end = self.__end
+ curr = end[1]
+ while curr is not end:
+ yield curr[0]
+ curr = curr[1]
+
+ def popitem(self, last=True):
+ if not self:
+ raise KeyError('dictionary is empty')
+ if last:
+ key = reversed(self).next()
+ else:
+ key = iter(self).next()
+ value = self.pop(key)
+ return key, value
+
+ def __reduce__(self):
+ items = [[k, self[k]] for k in self]
+ tmp = self.__map, self.__end
+ del self.__map, self.__end
+ inst_dict = vars(self).copy()
+ self.__map, self.__end = tmp
+ if inst_dict:
+ return (self.__class__, (items,), inst_dict)
+ return self.__class__, (items,)
+
+ def keys(self):
+ return list(self)
+
+ setdefault = DictMixin.setdefault
+ update = DictMixin.update
+ pop = DictMixin.pop
+ values = DictMixin.values
+ items = DictMixin.items
+ iterkeys = DictMixin.iterkeys
+ itervalues = DictMixin.itervalues
+ iteritems = DictMixin.iteritems
+
+ def __repr__(self):
+ if not self:
+ return '%s()' % (self.__class__.__name__,)
+ return '%s(%r)' % (self.__class__.__name__, self.items())
+
+ def copy(self):
+ return self.__class__(self)
+
+ @classmethod
+ def fromkeys(cls, iterable, value=None):
+ d = cls()
+ for key in iterable:
+ d[key] = value
+ return d
+
+ def __eq__(self, other):
+ if isinstance(other, OrderedDict):
+ if len(self) != len(other):
+ return False
+ for p, q in zip(self.items(), other.items()):
+ if p != q:
+ return False
+ return True
+ return dict.__eq__(self, other)
+
+ def __ne__(self, other):
+ return not self == other
+
--
1.7.0.4
^ permalink raw reply related [flat|nested] 37+ messages in thread
* [Qemu-devel] [PATCH v3 11/21] qapi: add qapi.py helper libraries
2011-06-14 2:31 [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v3 Michael Roth
` (9 preceding siblings ...)
2011-06-14 2:31 ` [Qemu-devel] [PATCH v3 10/21] qapi: add ordereddict.py helper library Michael Roth
@ 2011-06-14 2:31 ` Michael Roth
2011-06-14 2:31 ` [Qemu-devel] [PATCH v3 12/21] qapi: add qapi-types.py code generator Michael Roth
` (9 subsequent siblings)
20 siblings, 0 replies; 37+ messages in thread
From: Michael Roth @ 2011-06-14 2:31 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, Jes.Sorensen, agl, mdroth, lcapitulino
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
scripts/qapi.py | 203 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 203 insertions(+), 0 deletions(-)
create mode 100644 scripts/qapi.py
diff --git a/scripts/qapi.py b/scripts/qapi.py
new file mode 100644
index 0000000..56af232
--- /dev/null
+++ b/scripts/qapi.py
@@ -0,0 +1,203 @@
+#
+# QAPI helper library
+#
+# Copyright IBM, Corp. 2011
+#
+# Authors:
+# Anthony Liguori <aliguori@us.ibm.com>
+#
+# This work is licensed under the terms of the GNU GPLv2.
+# See the COPYING.LIB file in the top-level directory.
+
+from ordereddict import OrderedDict
+
+def tokenize(data):
+ while len(data):
+ if data[0] in ['{', '}', ':', ',', '[', ']']:
+ yield data[0]
+ data = data[1:]
+ elif data[0] in ' \n':
+ data = data[1:]
+ elif data[0] == "'":
+ data = data[1:]
+ string = ''
+ while data[0] != "'":
+ string += data[0]
+ data = data[1:]
+ data = data[1:]
+ yield string
+
+def parse(tokens):
+ if tokens[0] == '{':
+ ret = OrderedDict()
+ tokens = tokens[1:]
+ while tokens[0] != '}':
+ key = tokens[0]
+ tokens = tokens[1:]
+
+ tokens = tokens[1:] # :
+
+ value, tokens = parse(tokens)
+
+ if tokens[0] == ',':
+ tokens = tokens[1:]
+
+ ret[key] = value
+ tokens = tokens[1:]
+ return ret, tokens
+ elif tokens[0] == '[':
+ ret = []
+ tokens = tokens[1:]
+ while tokens[0] != ']':
+ value, tokens = parse(tokens)
+ if tokens[0] == ',':
+ tokens = tokens[1:]
+ ret.append(value)
+ tokens = tokens[1:]
+ return ret, tokens
+ else:
+ return tokens[0], tokens[1:]
+
+def evaluate(string):
+ return parse(map(lambda x: x, tokenize(string)))[0]
+
+def parse_schema(fp):
+ exprs = []
+ expr = ''
+ expr_eval = None
+
+ for line in fp:
+ if line.startswith('#') or line == '\n':
+ continue
+
+ if line.startswith(' '):
+ expr += line
+ elif expr:
+ expr_eval = evaluate(expr)
+ if expr_eval.has_key('enum'):
+ add_enum(expr_eval['enum'])
+ elif expr_eval.has_key('union'):
+ add_enum('%sKind' % expr_eval['union'])
+ exprs.append(expr_eval)
+ expr = line
+ else:
+ expr += line
+
+ if expr:
+ expr_eval = evaluate(expr)
+ if expr_eval.has_key('enum'):
+ add_enum(expr_eval['enum'])
+ elif expr_eval.has_key('union'):
+ add_enum('%sKind' % expr_eval['union'])
+ exprs.append(expr_eval)
+
+ return exprs
+
+def parse_args(typeinfo):
+ for member in typeinfo:
+ argname = member
+ argentry = typeinfo[member]
+ optional = False
+ structured = False
+ if member.startswith('*'):
+ argname = member[1:]
+ optional = True
+ if isinstance(argentry, OrderedDict):
+ structured = True
+ yield (argname, argentry, optional, structured)
+
+def de_camel_case(name):
+ new_name = ''
+ for ch in name:
+ if ch.isupper() and new_name:
+ new_name += '_'
+ if ch == '-':
+ new_name += '_'
+ else:
+ new_name += ch.lower()
+ return new_name
+
+def camel_case(name):
+ new_name = ''
+ first = True
+ for ch in name:
+ if ch in ['_', '-']:
+ first = True
+ elif first:
+ new_name += ch.upper()
+ first = False
+ else:
+ new_name += ch.lower()
+ return new_name
+
+def c_var(name):
+ return '_'.join(name.split('-')).lstrip("*")
+
+def c_list_type(name):
+ return '%sList' % name
+
+def type_name(name):
+ if type(name) == list:
+ return c_list_type(name[0])
+ return name
+
+enum_types = []
+
+def add_enum(name):
+ global enum_types
+ enum_types.append(name)
+
+def is_enum(name):
+ global enum_types
+ return (name in enum_types)
+
+def c_type(name):
+ if name == 'str':
+ return 'char *'
+ elif name == 'int':
+ return 'int64_t'
+ elif name == 'bool':
+ return 'bool'
+ elif name == 'number':
+ return 'double'
+ elif type(name) == list:
+ return '%s *' % c_list_type(name[0])
+ elif is_enum(name):
+ return name
+ elif name == None or len(name) == 0:
+ return 'void'
+ elif name == name.upper():
+ return '%sEvent *' % camel_case(name)
+ else:
+ return '%s *' % name
+
+def genindent(count):
+ ret = ""
+ for i in range(count):
+ ret += " "
+ return ret
+
+indent_level = 0
+
+def push_indent(indent_amount=4):
+ global indent_level
+ indent_level += indent_amount
+
+def pop_indent(indent_amount=4):
+ global indent_level
+ indent_level -= indent_amount
+
+def cgen(code, **kwds):
+ indent = genindent(indent_level)
+ lines = code.split('\n')
+ lines = map(lambda x: indent + x, lines)
+ return '\n'.join(lines) % kwds + '\n'
+
+def mcgen(code, **kwds):
+ return cgen('\n'.join(code.split('\n')[1:-1]), **kwds)
+
+def basename(filename):
+ return filename.split("/")[-1]
+
+def guardname(filename):
+ return filename.replace("/", "_").replace("-", "_").split(".")[0].upper()
--
1.7.0.4
^ permalink raw reply related [flat|nested] 37+ messages in thread
* [Qemu-devel] [PATCH v3 12/21] qapi: add qapi-types.py code generator
2011-06-14 2:31 [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v3 Michael Roth
` (10 preceding siblings ...)
2011-06-14 2:31 ` [Qemu-devel] [PATCH v3 11/21] qapi: add qapi.py helper libraries Michael Roth
@ 2011-06-14 2:31 ` Michael Roth
2011-06-15 19:11 ` Luiz Capitulino
2011-06-14 2:31 ` [Qemu-devel] [PATCH v3 13/21] qapi: add qapi-visit.py " Michael Roth
` (8 subsequent siblings)
20 siblings, 1 reply; 37+ messages in thread
From: Michael Roth @ 2011-06-14 2:31 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, Jes.Sorensen, agl, mdroth, lcapitulino
This is the code generator for qapi types. It will generation the
following files:
$(prefix)qapi-types.h - C types corresponding to types defined in
the schema you pass in
$(prefix)qapi-types.c - Cleanup functions for the above C types
The $(prefix) is used to as a namespace to keep the generated code from
one schema/code-generation separated from others so code and be
generated from multiple schemas with clobbering previously created code.
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
scripts/qapi-types.py | 230 +++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 230 insertions(+), 0 deletions(-)
create mode 100644 scripts/qapi-types.py
diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
new file mode 100644
index 0000000..c8d6b2f
--- /dev/null
+++ b/scripts/qapi-types.py
@@ -0,0 +1,230 @@
+#
+# QAPI types generator
+#
+# Copyright IBM, Corp. 2011
+#
+# Authors:
+# Anthony Liguori <aliguori@us.ibm.com>
+#
+# This work is licensed under the terms of the GNU GPLv2.
+# See the COPYING.LIB file in the top-level directory.
+
+from ordereddict import OrderedDict
+from qapi import *
+import sys
+import os
+import getopt
+
+def generate_fwd_struct(name, members):
+ return mcgen('''
+typedef struct %(name)s %(name)s;
+
+typedef struct %(name)sList
+{
+ %(name)s *value;
+ struct %(name)sList *next;
+} %(name)sList;
+''',
+ name=name)
+
+def generate_struct(structname, fieldname, members):
+ ret = mcgen('''
+struct %(name)s
+{
+''',
+ name=structname)
+
+ for argname, argentry, optional, structured in parse_args(members):
+ if optional:
+ ret += mcgen('''
+ bool has_%(c_name)s;
+''',
+ c_name=c_var(argname))
+ if structured:
+ push_indent()
+ ret += generate_struct("", argname, argentry)
+ pop_indent()
+ else:
+ ret += mcgen('''
+ %(c_type)s %(c_name)s;
+''',
+ c_type=c_type(argentry), c_name=c_var(argname))
+
+ if len(fieldname):
+ fieldname = " " + fieldname
+ ret += mcgen('''
+}%(field)s;
+''',
+ field=fieldname)
+
+ return ret
+
+def generate_handle(name, typeinfo):
+ return mcgen('''
+typedef struct %(name)s
+{
+ %(c_type)s handle;
+} %(name)s;
+
+typedef struct %(name)sList
+{
+ %(name)s *value;
+ struct %(name)sList *next;
+} %(name)sList;
+''',
+ name=name, c_type=c_type(typeinfo))
+
+def generate_enum(name, values):
+ ret = mcgen('''
+typedef enum %(name)s
+{
+''',
+ name=name)
+
+ i = 1
+ for value in values:
+ ret += mcgen('''
+ %(abbrev)s_%(value)s = %(i)d,
+''',
+ abbrev=de_camel_case(name).upper(),
+ value=c_var(value).upper(),
+ i=i)
+ i += 1
+
+ ret += mcgen('''
+} %(name)s;
+''',
+ name=name)
+
+ return ret
+
+def generate_union(name, typeinfo):
+ ret = mcgen('''
+struct %(name)s
+{
+ %(name)sKind kind;
+ union {
+''',
+ name=name)
+
+ for key in typeinfo:
+ ret += mcgen('''
+ %(c_type)s %(c_name)s;
+''',
+ c_type=c_type(typeinfo[key]),
+ c_name=c_var(key))
+
+ ret += mcgen('''
+ };
+};
+''')
+
+ return ret
+
+def generate_type_cleanup_decl(name):
+ ret = mcgen('''
+void qapi_free_%(type)s(%(c_type)s obj);
+''',
+ c_type=c_type(name),type=name)
+ return ret
+
+def generate_type_cleanup(name):
+ ret = mcgen('''
+void qapi_free_%(type)s(%(c_type)s obj)
+{
+ QapiDeallocVisitor *md;
+ Visitor *v;
+
+ if (!obj) {
+ return;
+ }
+
+ md = qapi_dealloc_visitor_new();
+ v = qapi_dealloc_get_visitor(md);
+ visit_type_%(type)s(v, &obj, NULL, NULL);
+ qapi_dealloc_visitor_cleanup(md);
+}
+''',
+ c_type=c_type(name),type=name)
+ return ret
+
+
+try:
+ opts, args = getopt.gnu_getopt(sys.argv[1:], "p:o:", ["prefix=", "output-dir="])
+except getopt.GetoptError, err:
+ print str(err)
+ sys.exit(1)
+
+output_dir = ""
+prefix = ""
+c_file = 'qapi-types.c'
+h_file = 'qapi-types.h'
+
+for o, a in opts:
+ if o in ("-p", "--prefix"):
+ prefix = a
+ elif o in ("-o", "--output-dir"):
+ output_dir = a + "/"
+
+c_file = output_dir + prefix + c_file
+h_file = output_dir + prefix + h_file
+
+if os.path.isdir(output_dir) == False:
+ os.makedirs(output_dir)
+
+fdef = open(c_file, 'w')
+fdecl = open(h_file, 'w')
+
+fdef.write(mcgen('''
+/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
+
+#include "qapi/qapi-dealloc-visitor.h"
+#include "%(prefix)sqapi-types.h"
+#include "%(prefix)sqapi-visit.h"
+
+''', prefix=prefix))
+
+fdecl.write(mcgen('''
+/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
+#ifndef %(guard)s
+#define %(guard)s
+
+#include "qapi/qapi-types-core.h"
+''',
+ guard=guardname(h_file)))
+
+exprs = parse_schema(sys.stdin)
+
+for expr in exprs:
+ ret = "\n"
+ if expr.has_key('type'):
+ ret += generate_fwd_struct(expr['type'], expr['data'])
+ elif expr.has_key('enum'):
+ ret += generate_enum(expr['enum'], expr['data'])
+ elif expr.has_key('union'):
+ ret += generate_fwd_struct(expr['union'], expr['data']) + "\n"
+ ret += generate_enum('%sKind' % expr['union'], expr['data'].keys())
+ else:
+ continue
+ fdecl.write(ret)
+
+for expr in exprs:
+ ret = "\n"
+ if expr.has_key('type'):
+ ret += generate_struct(expr['type'], "", expr['data']) + "\n"
+ ret += generate_type_cleanup_decl(expr['type'])
+ fdef.write(generate_type_cleanup(expr['type']) + "\n")
+ elif expr.has_key('handle'):
+ ret += generate_handle(expr['handle'], expr['data'])
+ elif expr.has_key('union'):
+ ret += generate_union(expr['union'], expr['data'])
+ else:
+ continue
+ fdecl.write(ret)
+
+fdecl.write('''
+#endif
+''')
+
+fdecl.flush()
+fdecl.close()
--
1.7.0.4
^ permalink raw reply related [flat|nested] 37+ messages in thread
* Re: [Qemu-devel] [PATCH v3 12/21] qapi: add qapi-types.py code generator
2011-06-14 2:31 ` [Qemu-devel] [PATCH v3 12/21] qapi: add qapi-types.py code generator Michael Roth
@ 2011-06-15 19:11 ` Luiz Capitulino
0 siblings, 0 replies; 37+ messages in thread
From: Luiz Capitulino @ 2011-06-15 19:11 UTC (permalink / raw)
To: Michael Roth; +Cc: aliguori, agl, qemu-devel, Jes.Sorensen
On Mon, 13 Jun 2011 21:31:17 -0500
Michael Roth <mdroth@linux.vnet.ibm.com> wrote:
> This is the code generator for qapi types. It will generation the
> following files:
>
> $(prefix)qapi-types.h - C types corresponding to types defined in
> the schema you pass in
> $(prefix)qapi-types.c - Cleanup functions for the above C types
>
> The $(prefix) is used to as a namespace to keep the generated code from
> one schema/code-generation separated from others so code and be
> generated from multiple schemas with clobbering previously created code.
>
> Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
> ---
> scripts/qapi-types.py | 230 +++++++++++++++++++++++++++++++++++++++++++++++++
> 1 files changed, 230 insertions(+), 0 deletions(-)
> create mode 100644 scripts/qapi-types.py
>
> diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
> new file mode 100644
> index 0000000..c8d6b2f
> --- /dev/null
> +++ b/scripts/qapi-types.py
> @@ -0,0 +1,230 @@
> +#
> +# QAPI types generator
> +#
> +# Copyright IBM, Corp. 2011
> +#
> +# Authors:
> +# Anthony Liguori <aliguori@us.ibm.com>
> +#
> +# This work is licensed under the terms of the GNU GPLv2.
> +# See the COPYING.LIB file in the top-level directory.
> +
> +from ordereddict import OrderedDict
> +from qapi import *
> +import sys
> +import os
> +import getopt
> +
> +def generate_fwd_struct(name, members):
> + return mcgen('''
> +typedef struct %(name)s %(name)s;
> +
> +typedef struct %(name)sList
> +{
> + %(name)s *value;
> + struct %(name)sList *next;
> +} %(name)sList;
> +''',
> + name=name)
> +
> +def generate_struct(structname, fieldname, members):
> + ret = mcgen('''
> +struct %(name)s
> +{
> +''',
> + name=structname)
> +
> + for argname, argentry, optional, structured in parse_args(members):
> + if optional:
> + ret += mcgen('''
> + bool has_%(c_name)s;
> +''',
> + c_name=c_var(argname))
> + if structured:
> + push_indent()
> + ret += generate_struct("", argname, argentry)
> + pop_indent()
> + else:
> + ret += mcgen('''
> + %(c_type)s %(c_name)s;
> +''',
> + c_type=c_type(argentry), c_name=c_var(argname))
> +
> + if len(fieldname):
> + fieldname = " " + fieldname
> + ret += mcgen('''
> +}%(field)s;
> +''',
> + field=fieldname)
> +
> + return ret
> +
> +def generate_handle(name, typeinfo):
> + return mcgen('''
> +typedef struct %(name)s
> +{
> + %(c_type)s handle;
> +} %(name)s;
> +
> +typedef struct %(name)sList
> +{
> + %(name)s *value;
> + struct %(name)sList *next;
> +} %(name)sList;
> +''',
> + name=name, c_type=c_type(typeinfo))
> +
> +def generate_enum(name, values):
> + ret = mcgen('''
> +typedef enum %(name)s
> +{
> +''',
> + name=name)
> +
> + i = 1
> + for value in values:
> + ret += mcgen('''
> + %(abbrev)s_%(value)s = %(i)d,
> +''',
> + abbrev=de_camel_case(name).upper(),
> + value=c_var(value).upper(),
> + i=i)
> + i += 1
> +
> + ret += mcgen('''
> +} %(name)s;
> +''',
> + name=name)
> +
> + return ret
> +
> +def generate_union(name, typeinfo):
> + ret = mcgen('''
> +struct %(name)s
> +{
> + %(name)sKind kind;
> + union {
> +''',
> + name=name)
> +
> + for key in typeinfo:
> + ret += mcgen('''
> + %(c_type)s %(c_name)s;
> +''',
> + c_type=c_type(typeinfo[key]),
> + c_name=c_var(key))
> +
> + ret += mcgen('''
> + };
> +};
> +''')
> +
> + return ret
> +
> +def generate_type_cleanup_decl(name):
> + ret = mcgen('''
> +void qapi_free_%(type)s(%(c_type)s obj);
> +''',
> + c_type=c_type(name),type=name)
> + return ret
> +
> +def generate_type_cleanup(name):
> + ret = mcgen('''
> +void qapi_free_%(type)s(%(c_type)s obj)
> +{
> + QapiDeallocVisitor *md;
> + Visitor *v;
> +
> + if (!obj) {
> + return;
> + }
> +
> + md = qapi_dealloc_visitor_new();
> + v = qapi_dealloc_get_visitor(md);
> + visit_type_%(type)s(v, &obj, NULL, NULL);
> + qapi_dealloc_visitor_cleanup(md);
> +}
> +''',
> + c_type=c_type(name),type=name)
> + return ret
> +
> +
> +try:
> + opts, args = getopt.gnu_getopt(sys.argv[1:], "p:o:", ["prefix=", "output-dir="])
> +except getopt.GetoptError, err:
> + print str(err)
> + sys.exit(1)
> +
> +output_dir = ""
> +prefix = ""
> +c_file = 'qapi-types.c'
> +h_file = 'qapi-types.h'
> +
> +for o, a in opts:
> + if o in ("-p", "--prefix"):
> + prefix = a
> + elif o in ("-o", "--output-dir"):
> + output_dir = a + "/"
> +
> +c_file = output_dir + prefix + c_file
> +h_file = output_dir + prefix + h_file
> +
> +if os.path.isdir(output_dir) == False:
> + os.makedirs(output_dir)
> +
> +fdef = open(c_file, 'w')
> +fdecl = open(h_file, 'w')
> +
> +fdef.write(mcgen('''
> +/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
No license, I think all the code generators forget this.
> +
> +#include "qapi/qapi-dealloc-visitor.h"
> +#include "%(prefix)sqapi-types.h"
> +#include "%(prefix)sqapi-visit.h"
> +
> +''', prefix=prefix))
> +
> +fdecl.write(mcgen('''
> +/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
> +#ifndef %(guard)s
> +#define %(guard)s
> +
> +#include "qapi/qapi-types-core.h"
> +''',
> + guard=guardname(h_file)))
> +
> +exprs = parse_schema(sys.stdin)
> +
> +for expr in exprs:
> + ret = "\n"
> + if expr.has_key('type'):
> + ret += generate_fwd_struct(expr['type'], expr['data'])
> + elif expr.has_key('enum'):
> + ret += generate_enum(expr['enum'], expr['data'])
> + elif expr.has_key('union'):
> + ret += generate_fwd_struct(expr['union'], expr['data']) + "\n"
> + ret += generate_enum('%sKind' % expr['union'], expr['data'].keys())
> + else:
> + continue
> + fdecl.write(ret)
> +
> +for expr in exprs:
> + ret = "\n"
> + if expr.has_key('type'):
> + ret += generate_struct(expr['type'], "", expr['data']) + "\n"
> + ret += generate_type_cleanup_decl(expr['type'])
> + fdef.write(generate_type_cleanup(expr['type']) + "\n")
> + elif expr.has_key('handle'):
> + ret += generate_handle(expr['handle'], expr['data'])
> + elif expr.has_key('union'):
> + ret += generate_union(expr['union'], expr['data'])
> + else:
> + continue
> + fdecl.write(ret)
> +
> +fdecl.write('''
> +#endif
> +''')
> +
> +fdecl.flush()
> +fdecl.close()
^ permalink raw reply [flat|nested] 37+ messages in thread
* [Qemu-devel] [PATCH v3 13/21] qapi: add qapi-visit.py code generator
2011-06-14 2:31 [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v3 Michael Roth
` (11 preceding siblings ...)
2011-06-14 2:31 ` [Qemu-devel] [PATCH v3 12/21] qapi: add qapi-types.py code generator Michael Roth
@ 2011-06-14 2:31 ` Michael Roth
2011-06-14 2:31 ` [Qemu-devel] [PATCH v3 14/21] qapi: add qapi-commands.py " Michael Roth
` (7 subsequent siblings)
20 siblings, 0 replies; 37+ messages in thread
From: Michael Roth @ 2011-06-14 2:31 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, Jes.Sorensen, agl, mdroth, lcapitulino
This is the code generator for qapi visiter functions used to
marshal/unmarshal/dealloc qapi types. It generates the following 2
files:
$(prefix)qapi-visit.c: visiter function for a particular c type, used
to automagically convert qobjects into the
corresponding C type and vice-versa, and well
as for deallocation memory for an existing C
type
$(prefix)qapi-visit.h: declarations for previously mentioned visiter
functions
$(prefix) is used as decribed for qapi-types.py
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
scripts/qapi-visit.py | 235 +++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 235 insertions(+), 0 deletions(-)
create mode 100644 scripts/qapi-visit.py
diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
new file mode 100644
index 0000000..0eb45c9
--- /dev/null
+++ b/scripts/qapi-visit.py
@@ -0,0 +1,235 @@
+#
+# QAPI visitor generator
+#
+# Copyright IBM, Corp. 2011
+#
+# Authors:
+# Anthony Liguori <aliguori@us.ibm.com>
+# Michael Roth <mdroth@linux.vnet.ibm.com>
+#
+# This work is licensed under the terms of the GNU GPLv2.
+# See the COPYING.LIB file in the top-level directory.
+
+from ordereddict import OrderedDict
+from qapi import *
+import sys
+import os
+import getopt
+
+def generate_visit_struct_body(field_prefix, members):
+ ret = ""
+ if len(field_prefix):
+ field_prefix = field_prefix + "."
+ for argname, argentry, optional, structured in parse_args(members):
+ if optional:
+ ret += mcgen('''
+visit_start_optional(m, (obj && *obj) ? &(*obj)->%(c_prefix)shas_%(c_name)s : NULL, "%(name)s", errp);
+if ((*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 += mcgen('''
+visit_start_struct(m, NULL, "", "%(name)s", 0, errp);
+''',
+ name=argname)
+ ret += generate_visit_struct_body(field_prefix + argname, argentry)
+ ret += mcgen('''
+visit_end_struct(m, errp);
+''')
+ else:
+ ret += mcgen('''
+visit_type_%(type)s(m, (obj && *obj) ? &(*obj)->%(c_prefix)s%(c_name)s : NULL, "%(name)s", errp);
+''',
+ c_prefix=c_var(field_prefix), prefix=field_prefix,
+ type=type_name(argentry), c_name=c_var(argname),
+ name=argname)
+
+ if optional:
+ pop_indent()
+ ret += mcgen('''
+}
+visit_end_optional(m, errp);
+''')
+ return ret
+
+def generate_visit_struct(name, members):
+ ret = mcgen('''
+
+void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp)
+{
+ visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), errp);
+''',
+ name=name)
+ push_indent()
+ ret += generate_visit_struct_body("", members)
+ pop_indent()
+
+ ret += mcgen('''
+ visit_end_struct(m, errp);
+}
+''')
+ return ret
+
+def generate_visit_list(name, members):
+ return mcgen('''
+
+void visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char *name, Error **errp)
+{
+ GenericList *i;
+
+ visit_start_list(m, name, errp);
+
+ for (i = visit_next_list(m, (GenericList **)obj, errp); i; i = visit_next_list(m, &i, errp)) {
+ %(name)sList *native_i = (%(name)sList *)i;
+ visit_type_%(name)s(m, &native_i->value, NULL, errp);
+ }
+
+ visit_end_list(m, errp);
+}
+''',
+ name=name)
+
+def generate_visit_handle(name, typeinfo):
+ return mcgen('''
+
+void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp)
+{
+ visit_start_handle(m, (void **)obj, "%(name)s", name, errp);
+ visit_type_%(type_name)s(m, &(*obj)->handle, "handle", errp);
+ visit_end_handle(m, errp);
+}
+''',
+ name=name, type_name=type_name(typeinfo))
+
+def generate_visit_enum(name, members):
+ return mcgen('''
+
+void visit_type_%(name)s(Visitor *m, %(name)s * obj, const char *name, Error **errp)
+{
+ visit_type_enum(m, (int *)obj, "%(name)s", name, errp);
+}
+''',
+ name=name)
+
+def generate_visit_union(name, members):
+ ret = generate_visit_enum('%sKind' % name, members.keys())
+
+ ret += mcgen('''
+
+void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp)
+{
+}
+''',
+ name=name)
+
+ return ret
+
+def generate_declaration(name, members, genlist=True):
+ ret = mcgen('''
+
+void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp);
+''',
+ name=name)
+
+ if genlist:
+ ret += mcgen('''
+void visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char *name, Error **errp);
+''',
+ name=name)
+
+ return ret
+
+def generate_decl_enum(name, members, genlist=True):
+ return mcgen('''
+
+void visit_type_%(name)s(Visitor *m, %(name)s * obj, const char *name, Error **errp);
+''',
+ name=name)
+
+try:
+ opts, args = getopt.gnu_getopt(sys.argv[1:], "p:o:", ["prefix=", "output-dir="])
+except getopt.GetoptError, err:
+ print str(err)
+ sys.exit(1)
+
+output_dir = ""
+prefix = ""
+c_file = 'qapi-visit.c'
+h_file = 'qapi-visit.h'
+
+for o, a in opts:
+ if o in ("-p", "--prefix"):
+ prefix = a
+ elif o in ("-o", "--output-dir"):
+ output_dir = a + "/"
+
+c_file = output_dir + prefix + c_file
+h_file = output_dir + prefix + h_file
+
+if os.path.isdir(output_dir) == False:
+ os.makedirs(output_dir)
+
+fdef = open(c_file, 'w')
+fdecl = open(h_file, 'w')
+
+fdef.write(mcgen('''
+/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
+
+#include "%(header)s"
+''',
+ header=basename(h_file)))
+
+fdecl.write(mcgen('''
+/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
+
+#ifndef %(guard)s
+#define %(guard)s
+
+#include "qapi/qapi-visit-core.h"
+#include "%(prefix)sqapi-types.h"
+''',
+ prefix=prefix, guard=guardname(h_file)))
+
+exprs = parse_schema(sys.stdin)
+
+for expr in exprs:
+ if expr.has_key('type'):
+ ret = generate_visit_struct(expr['type'], expr['data'])
+ ret += generate_visit_list(expr['type'], expr['data'])
+ fdef.write(ret)
+
+ ret = generate_declaration(expr['type'], expr['data'])
+ fdecl.write(ret)
+ elif expr.has_key('union'):
+ ret = generate_visit_union(expr['union'], expr['data'])
+ fdef.write(ret)
+
+ ret = generate_decl_enum('%sKind' % expr['union'], expr['data'].keys())
+ ret += generate_declaration(expr['union'], expr['data'])
+ fdecl.write(ret)
+ elif expr.has_key('enum'):
+ ret = generate_visit_enum(expr['enum'], expr['data'])
+ fdef.write(ret)
+
+ ret = generate_decl_enum(expr['enum'], expr['data'])
+ fdecl.write(ret)
+ elif expr.has_key('handle'):
+ ret = generate_visit_handle(expr['handle'], expr['data'])
+ fdef.write(ret)
+
+ ret = generate_declaration(expr['handle'], expr['data'], False)
+ fdecl.write(ret)
+
+fdecl.write('''
+#endif
+''')
+
+fdecl.flush()
+fdecl.close()
+
+fdef.flush()
+fdef.close()
+
--
1.7.0.4
^ permalink raw reply related [flat|nested] 37+ messages in thread
* [Qemu-devel] [PATCH v3 14/21] qapi: add qapi-commands.py code generator
2011-06-14 2:31 [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v3 Michael Roth
` (12 preceding siblings ...)
2011-06-14 2:31 ` [Qemu-devel] [PATCH v3 13/21] qapi: add qapi-visit.py " Michael Roth
@ 2011-06-14 2:31 ` Michael Roth
2011-06-14 2:31 ` [Qemu-devel] [PATCH v3 15/21] qapi: test schema used for unit tests Michael Roth
` (6 subsequent siblings)
20 siblings, 0 replies; 37+ messages in thread
From: Michael Roth @ 2011-06-14 2:31 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, Jes.Sorensen, agl, mdroth, lcapitulino
This is the code generator for qapi command marshaling/dispatch.
Currently only generators for synchronous qapi/qmp functions are
supported. This script generates the following files:
$(prefix)qmp-marshal.c: command marshal/dispatch functions for each
QMP command defined in the schema. Functions
generated by qapi-visit.py are used to
convert qobjects recieved from the wire into
function parameters, and uses the same
visiter functions to convert native C return
values to qobjects from transmission back
over the wire.
$(prefix)qmp-commands.h: Function prototypes for the QMP commands
specified in the schema.
$(prefix) is used in the same manner as with qapi-types.py
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
scripts/qapi-commands.py | 355 ++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 355 insertions(+), 0 deletions(-)
create mode 100644 scripts/qapi-commands.py
diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py
new file mode 100644
index 0000000..23821ba
--- /dev/null
+++ b/scripts/qapi-commands.py
@@ -0,0 +1,355 @@
+#
+# QAPI command marshaller generator
+#
+# Copyright IBM, Corp. 2011
+#
+# Authors:
+# Anthony Liguori <aliguori@us.ibm.com>
+# Michael Roth <mdroth@linux.vnet.ibm.com>
+#
+# This work is licensed under the terms of the GNU GPLv2.
+# See the COPYING.LIB file in the top-level directory.
+
+from ordereddict import OrderedDict
+from qapi import *
+import sys
+import os
+import getopt
+
+def generate_decl_enum(name, members, genlist=True):
+ return mcgen('''
+
+void visit_type_%(name)s(Visitor *m, %(name)s * obj, const char *name, Error **errp);
+''',
+ name=name)
+
+def generate_command_decl(name, args, ret_type):
+ arglist=""
+ for argname, argtype, optional, structured in parse_args(args):
+ argtype = c_type(argtype)
+ if argtype == "char *":
+ argtype = "const char *"
+ if optional:
+ arglist += "bool has_%s, " % c_var(argname)
+ arglist += "%s %s, " % (argtype, c_var(argname))
+ return mcgen('''
+%(ret_type)s qmp_%(name)s(%(args)sError **errp);
+''',
+ ret_type=c_type(ret_type), name=c_var(name), args=arglist).strip()
+
+def gen_sync_call(name, args, ret_type, indent=0):
+ ret = ""
+ arglist=""
+ retval=""
+ if ret_type:
+ retval = "retval = "
+ for argname, argtype, optional, structured in parse_args(args):
+ if optional:
+ arglist += "has_%s, " % c_var(argname)
+ arglist += "%s, " % (c_var(argname))
+ push_indent(indent)
+ ret = mcgen('''
+%(retval)sqmp_%(name)s(%(args)serrp);
+
+''',
+ name=c_var(name), args=arglist, retval=retval).rstrip()
+ if ret_type:
+ ret += "\n" + mcgen(''''
+%(marshal_output_call)s
+''',
+ marshal_output_call=gen_marshal_output_call(name, ret_type)).rstrip()
+ pop_indent(indent)
+ return ret.rstrip()
+
+
+def gen_marshal_output_call(name, ret_type):
+ if not ret_type:
+ return ""
+ return "qmp_marshal_output_%s(retval, ret, errp);" % c_var(name)
+
+def gen_visitor_output_containers_decl(ret_type):
+ ret = ""
+ push_indent()
+ if ret_type:
+ ret += mcgen('''
+QmpOutputVisitor *mo;
+QapiDeallocVisitor *md;
+Visitor *v;
+''')
+ pop_indent()
+
+ return ret
+
+def gen_visitor_input_containers_decl(args):
+ ret = ""
+
+ push_indent()
+ if len(args) > 0:
+ ret += mcgen('''
+QmpInputVisitor *mi;
+QapiDeallocVisitor *md;
+Visitor *v;
+''')
+ pop_indent()
+
+ return ret.rstrip()
+
+def gen_visitor_input_vars_decl(args):
+ ret = ""
+ push_indent()
+ for argname, argtype, optional, structured in parse_args(args):
+ if optional:
+ ret += mcgen('''
+bool has_%(argname)s = false;
+''',
+ argname=c_var(argname))
+ if c_type(argtype).endswith("*"):
+ ret += mcgen('''
+%(argtype)s %(argname)s = NULL;
+''',
+ argname=c_var(argname), argtype=c_type(argtype))
+ else:
+ ret += mcgen('''
+%(argtype)s %(argname)s;
+''',
+ argname=c_var(argname), argtype=c_type(argtype))
+
+ pop_indent()
+ return ret.rstrip()
+
+def gen_visitor_input_block(args, obj, dealloc=False):
+ ret = ""
+ if len(args) == 0:
+ return ret
+
+ push_indent()
+
+ if dealloc:
+ ret += mcgen('''
+md = qapi_dealloc_visitor_new();
+v = qapi_dealloc_get_visitor(md);
+''')
+ else:
+ ret += mcgen('''
+mi = qmp_input_visitor_new(%(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);
+if (has_%(c_name)s) {
+''',
+ c_name=c_var(argname), name=argname)
+ push_indent()
+ ret += mcgen('''
+visit_type_%(argtype)s(v, &%(c_name)s, "%(name)s", errp);
+''',
+ c_name=c_var(argname), name=argname, argtype=argtype)
+ if optional:
+ pop_indent()
+ ret += mcgen('''
+}
+visit_end_optional(v, errp);
+''')
+
+ if dealloc:
+ ret += mcgen('''
+qapi_dealloc_visitor_cleanup(md);
+''')
+ else:
+ ret += mcgen('''
+qmp_input_visitor_cleanup(mi);
+''')
+ pop_indent()
+ return ret.rstrip()
+
+def gen_marshal_output(name, args, ret_type):
+ if not ret_type:
+ return ""
+ 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();
+ QmpOutputVisitor *mo = qmp_output_visitor_new();
+ Visitor *v;
+
+ v = qmp_output_get_visitor(mo);
+ visit_type_%(ret_type)s(v, &ret_in, "unused", errp);
+ if (!error_is_set(errp)) {
+ *ret_out = qmp_output_get_qobject(mo);
+ }
+ qmp_output_visitor_cleanup(mo);
+ v = qapi_dealloc_get_visitor(md);
+ visit_type_%(ret_type)s(v, &ret_in, "unused", errp);
+ qapi_dealloc_visitor_cleanup(md);
+}
+''',
+ c_ret_type=c_type(ret_type), c_name=c_var(name), ret_type=ret_type)
+
+ return ret
+
+def gen_marshal_input(name, args, ret_type):
+ ret = mcgen('''
+static void qmp_marshal_input_%(c_name)s(QDict *args, QObject **ret, Error **errp)
+{
+''',
+ c_name=c_var(name))
+
+ if ret_type:
+ if c_type(ret_type).endswith("*"):
+ retval = " %s retval = NULL;" % c_type(ret_type)
+ else:
+ retval = " %s retval;" % c_type(ret_type)
+ ret += mcgen('''
+%(retval)s
+''',
+ retval=retval)
+
+ if len(args) > 0:
+ ret += mcgen('''
+%(visitor_input_containers_decl)s
+%(visitor_input_vars_decl)s
+
+%(visitor_input_block)s
+
+''',
+ visitor_input_containers_decl=gen_visitor_input_containers_decl(args),
+ visitor_input_vars_decl=gen_visitor_input_vars_decl(args),
+ visitor_input_block=gen_visitor_input_block(args, "QOBJECT(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('''
+
+out:
+''')
+ ret += mcgen('''
+%(visitor_input_block_cleanup)s
+ return;
+}
+''',
+ visitor_input_block_cleanup=gen_visitor_input_block(args, None, dealloc=True))
+ return ret
+
+def gen_registry(commands):
+ registry=""
+ push_indent()
+ for cmd in commands:
+ registry += mcgen('''
+qmp_register_command("%(name)s", qmp_marshal_input_%(c_name)s);
+''',
+ name=cmd['command'], c_name=c_var(cmd['command']))
+ pop_indent()
+ ret = mcgen('''
+static void qmp_init_marshal(void)
+{
+%(registry)s
+}
+
+qapi_init(qmp_init_marshal);
+''',
+ registry=registry.rstrip())
+ return ret
+
+def gen_command_decl_prologue(header, guard, prefix=""):
+ ret = mcgen('''
+/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
+
+#ifndef %(guard)s
+#define %(guard)s
+
+#include "%(prefix)sqapi-types.h"
+#include "error.h"
+
+''',
+ header=basename(h_file), guard=guardname(h_file), prefix=prefix)
+ return ret
+
+def gen_command_def_prologue(prefix="", proxy=False):
+ ret = mcgen('''
+/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
+
+#include "qemu-objects.h"
+#include "qapi/qmp-core.h"
+#include "qapi/qapi-visit-core.h"
+#include "qapi/qmp-output-visitor.h"
+#include "qapi/qmp-input-visitor.h"
+#include "qapi/qapi-dealloc-visitor.h"
+#include "%(prefix)sqapi-types.h"
+#include "%(prefix)sqapi-visit.h"
+
+''',
+ prefix=prefix)
+ if not proxy:
+ ret += '#include "%sqmp-commands.h"' % prefix
+ return ret + "\n"
+
+
+try:
+ opts, args = getopt.gnu_getopt(sys.argv[1:], "p:o:", ["prefix=", "output-dir=", "type="])
+except getopt.GetoptError, err:
+ print str(err)
+ sys.exit(1)
+
+output_dir = ""
+prefix = ""
+dispatch_type = "sync"
+c_file = 'qmp-marshal.c'
+h_file = 'qmp-commands.h'
+
+for o, a in opts:
+ if o in ("-p", "--prefix"):
+ prefix = a
+ elif o in ("-o", "--output-dir"):
+ output_dir = a + "/"
+ elif o in ("-t", "--type"):
+ dispatch_type = a
+
+c_file = output_dir + prefix + c_file
+h_file = output_dir + prefix + h_file
+
+if os.path.isdir(output_dir) == False:
+ os.makedirs(output_dir)
+
+exprs = parse_schema(sys.stdin)
+commands = filter(lambda expr: expr.has_key('command'), exprs)
+
+if dispatch_type == "sync":
+ fdecl = open(h_file, 'w')
+ fdef = open(c_file, 'w')
+ ret = gen_command_decl_prologue(header=basename(h_file), guard=guardname(h_file), prefix=prefix)
+ fdecl.write(ret)
+ ret = gen_command_def_prologue(prefix=prefix)
+ fdef.write(ret)
+
+ for cmd in commands:
+ arglist = []
+ ret_type = None
+ if cmd.has_key('data'):
+ arglist = cmd['data']
+ if cmd.has_key('returns'):
+ ret_type = cmd['returns']
+ ret = generate_command_decl(cmd['command'], arglist, ret_type) + "\n"
+ fdecl.write(ret)
+ if ret_type:
+ ret = gen_marshal_output(cmd['command'], arglist, ret_type) + "\n"
+ fdef.write(ret)
+ ret = gen_marshal_input(cmd['command'], arglist, ret_type) + "\n"
+ fdef.write(ret)
+
+ fdecl.write("\n#endif");
+ ret = gen_registry(commands)
+ fdef.write(ret)
+
+ fdef.flush()
+ fdef.close()
+ fdecl.flush()
+ fdecl.close()
--
1.7.0.4
^ permalink raw reply related [flat|nested] 37+ messages in thread
* [Qemu-devel] [PATCH v3 15/21] qapi: test schema used for unit tests
2011-06-14 2:31 [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v3 Michael Roth
` (13 preceding siblings ...)
2011-06-14 2:31 ` [Qemu-devel] [PATCH v3 14/21] qapi: add qapi-commands.py " Michael Roth
@ 2011-06-14 2:31 ` Michael Roth
2011-06-14 2:31 ` [Qemu-devel] [PATCH v3 16/21] qapi: add test-visitor, tests for gen. visitor code Michael Roth
` (5 subsequent siblings)
20 siblings, 0 replies; 37+ messages in thread
From: Michael Roth @ 2011-06-14 2:31 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, Jes.Sorensen, agl, mdroth, lcapitulino
This is how QMP commands/parameters/types would be defined. We use a
subset of that functionality here to implement functions/types for unit
testing.
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
qapi-schema-test.json | 22 ++++++++++++++++++++++
1 files changed, 22 insertions(+), 0 deletions(-)
create mode 100644 qapi-schema-test.json
diff --git a/qapi-schema-test.json b/qapi-schema-test.json
new file mode 100644
index 0000000..3acedad
--- /dev/null
+++ b/qapi-schema-test.json
@@ -0,0 +1,22 @@
+# *-*- Mode: Python -*-*
+
+# for testing enums
+{ 'enum': 'EnumOne',
+ 'data': [ 'value1', 'value2', 'value3' ] }
+{ 'type': 'NestedEnumsOne',
+ 'data': { 'enum1': 'EnumOne', '*enum2': 'EnumOne', 'enum3': 'EnumOne', '*enum4': 'EnumOne' } }
+
+# for testing nested structs
+{ 'type': 'UserDefOne',
+ 'data': { 'integer': 'int', 'string': 'str' } }
+
+{ 'type': 'UserDefTwo',
+ 'data': { 'string': 'str',
+ 'dict': { 'string': 'str',
+ 'dict': { 'userdef': 'UserDefOne', 'string': 'str' },
+ '*dict2': { 'userdef': 'UserDefOne', 'string': 'str' } } } }
+
+# testing commands
+{ 'command': 'user_def_cmd', 'data': {} }
+{ 'command': 'user_def_cmd1', 'data': {'ud1a': 'UserDefOne'} }
+{ 'command': 'user_def_cmd2', 'data': {'ud1a': 'UserDefOne', 'ud1b': 'UserDefOne'}, 'returns': 'UserDefTwo' }
--
1.7.0.4
^ permalink raw reply related [flat|nested] 37+ messages in thread
* [Qemu-devel] [PATCH v3 16/21] qapi: add test-visitor, tests for gen. visitor code
2011-06-14 2:31 [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v3 Michael Roth
` (14 preceding siblings ...)
2011-06-14 2:31 ` [Qemu-devel] [PATCH v3 15/21] qapi: test schema used for unit tests Michael Roth
@ 2011-06-14 2:31 ` Michael Roth
2011-06-14 2:31 ` [Qemu-devel] [PATCH v3 17/21] qapi: configure, Fix build issue when using seperate build dir Michael Roth
` (4 subsequent siblings)
20 siblings, 0 replies; 37+ messages in thread
From: Michael Roth @ 2011-06-14 2:31 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, Jes.Sorensen, agl, mdroth, lcapitulino
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
test-visitor.c | 305 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 305 insertions(+), 0 deletions(-)
create mode 100644 test-visitor.c
diff --git a/test-visitor.c b/test-visitor.c
new file mode 100644
index 0000000..5b2f138
--- /dev/null
+++ b/test-visitor.c
@@ -0,0 +1,305 @@
+#include <glib.h>
+#include "qapi/qmp-output-visitor.h"
+#include "qapi/qmp-input-visitor.h"
+#include "test-qapi-types.h"
+#include "test-qapi-visit.h"
+#include "qemu-objects.h"
+
+typedef struct TestStruct
+{
+ int64_t x;
+ int64_t y;
+} TestStruct;
+
+typedef struct TestStructList
+{
+ TestStruct *value;
+ struct TestStructList *next;
+} TestStructList;
+
+static void visit_type_TestStruct(Visitor *v, TestStruct **obj, const char *name, Error **errp)
+{
+ visit_start_struct(v, (void **)obj, "TestStruct", name, sizeof(TestStruct), errp);
+ visit_type_int(v, &(*obj)->x, "x", errp);
+ visit_type_int(v, &(*obj)->y, "y", errp);
+ visit_end_struct(v, errp);
+}
+
+static void visit_type_TestStructList(Visitor *m, TestStructList ** obj, const char *name, Error **errp)
+{
+ GenericList *i;
+
+ visit_start_list(m, name, errp);
+
+ for (i = visit_next_list(m, (GenericList **)obj, errp); i; i = visit_next_list(m, &i, errp)) {
+ TestStructList *native_i = (TestStructList *)i;
+ visit_type_TestStruct(m, &native_i->value, NULL, errp);
+ }
+
+ visit_end_list(m, errp);
+}
+
+/* test core visitor methods */
+static void test_visitor_core(void)
+{
+ QmpOutputVisitor *mo;
+ QmpInputVisitor *mi;
+ Visitor *v;
+ TestStruct ts = { 42, 82 };
+ TestStruct *pts = &ts;
+ TestStructList *lts = NULL;
+ Error *err = NULL;
+ QObject *obj;
+ QString *str;
+ int64_t value = 0;
+
+ mo = qmp_output_visitor_new();
+ v = qmp_output_get_visitor(mo);
+
+ visit_type_TestStruct(v, &pts, NULL, &err);
+
+ obj = qmp_output_get_qobject(mo);
+
+ str = qobject_to_json(obj);
+
+ printf("%s\n", qstring_get_str(str));
+
+ QDECREF(str);
+
+ obj = QOBJECT(qint_from_int(0x42));
+
+ mi = qmp_input_visitor_new(obj);
+ v = qmp_input_get_visitor(mi);
+
+ visit_type_int(v, &value, NULL, &err);
+ if (err) {
+ g_error("%s", error_get_pretty(err));
+ }
+
+ g_assert(value == 0x42);
+
+ qobject_decref(obj);
+
+ obj = qobject_from_json("{'x': 42, 'y': 84}");
+ mi = qmp_input_visitor_new(obj);
+ v = qmp_input_get_visitor(mi);
+
+ pts = NULL;
+
+ visit_type_TestStruct(v, &pts, NULL, &err);
+ if (err) {
+ g_error("%s", error_get_pretty(err));
+ }
+
+ g_assert(pts != NULL);
+ g_assert(pts->x == 42);
+ g_assert(pts->y == 84);
+
+ qobject_decref(obj);
+
+ obj = qobject_from_json("[{'x': 42, 'y': 84}, {'x': 12, 'y': 24}]");
+ mi = qmp_input_visitor_new(obj);
+ v = qmp_input_get_visitor(mi);
+
+ visit_type_TestStructList(v, <s, NULL, &err);
+ if (err) {
+ g_error("%s", error_get_pretty(err));
+ }
+
+ g_assert(lts != NULL);
+ g_assert(lts->value->x == 42);
+ g_assert(lts->value->y == 84);
+
+ lts = lts->next;
+ g_assert(lts != NULL);
+ g_assert(lts->value->x == 12);
+ g_assert(lts->value->y == 24);
+
+ g_assert(lts->next == NULL);
+
+ qobject_decref(obj);
+}
+
+/* test deep nesting with refs to other user-defined types */
+static void test_nested_structs(void)
+{
+ QmpOutputVisitor *mo;
+ QmpInputVisitor *mi;
+ Visitor *v;
+ UserDefOne ud1;
+ UserDefOne *ud1_p = &ud1, *ud1c_p = NULL;
+ UserDefTwo ud2;
+ UserDefTwo *ud2_p = &ud2, *ud2c_p = NULL;
+ Error *err = NULL;
+ QObject *obj;
+ QString *str;
+
+ ud1.integer = 42;
+ ud1.string = strdup("fourty two");
+
+ /* sanity check */
+ mo = qmp_output_visitor_new();
+ v = qmp_output_get_visitor(mo);
+ visit_type_UserDefOne(v, &ud1_p, "o_O", &err);
+ if (err) {
+ g_error("%s", error_get_pretty(err));
+ }
+ obj = qmp_output_get_qobject(mo);
+ g_assert(obj);
+ qobject_decref(obj);
+
+ ud2.string = strdup("fourty three");
+ ud2.dict.string = strdup("fourty four");
+ ud2.dict.dict.userdef = ud1_p;
+ ud2.dict.dict.string = strdup("fourty five");
+ ud2.dict.has_dict2 = true;
+ ud2.dict.dict2.userdef = ud1_p;
+ ud2.dict.dict2.string = strdup("fourty six");
+
+ /* c type -> qobject */
+ mo = qmp_output_visitor_new();
+ v = qmp_output_get_visitor(mo);
+ visit_type_UserDefTwo(v, &ud2_p, "unused", &err);
+ if (err) {
+ g_error("%s", error_get_pretty(err));
+ }
+ obj = qmp_output_get_qobject(mo);
+ g_assert(obj);
+ str = qobject_to_json_pretty(obj);
+ g_print("%s\n", qstring_get_str(str));
+ QDECREF(str);
+
+ /* qobject -> c type, should match original struct */
+ mi = qmp_input_visitor_new(obj);
+ v = qmp_input_get_visitor(mi);
+ visit_type_UserDefTwo(v, &ud2c_p, NULL, &err);
+ if (err) {
+ g_error("%s", error_get_pretty(err));
+ }
+
+ g_assert(!g_strcmp0(ud2c_p->string, ud2.string));
+ g_assert(!g_strcmp0(ud2c_p->dict.string, ud2.dict.string));
+
+ ud1c_p = ud2c_p->dict.dict.userdef;
+ g_assert(ud1c_p->integer == ud1_p->integer);
+ g_assert(!g_strcmp0(ud1c_p->string, ud1_p->string));
+
+ g_assert(!g_strcmp0(ud2c_p->dict.dict.string, ud2.dict.dict.string));
+
+ ud1c_p = ud2c_p->dict.dict2.userdef;
+ g_assert(ud1c_p->integer == ud1_p->integer);
+ g_assert(!g_strcmp0(ud1c_p->string, ud1_p->string));
+
+ g_assert(!g_strcmp0(ud2c_p->dict.dict2.string, ud2.dict.dict2.string));
+ qemu_free(ud1.string);
+ qemu_free(ud2.string);
+ qemu_free(ud2.dict.string);
+ qemu_free(ud2.dict.dict.string);
+ qemu_free(ud2.dict.dict2.string);
+
+ qapi_free_UserDefTwo(ud2c_p);
+
+ qobject_decref(obj);
+}
+
+/* test enum values */
+static void test_enums(void)
+{
+ QmpOutputVisitor *mo;
+ QmpInputVisitor *mi;
+ Visitor *v;
+ EnumOne enum1 = ENUM_ONE_VALUE1, enum1_cpy = ENUM_ONE_VALUE2;
+ Error *err = NULL;
+ QObject *obj;
+ QString *str;
+
+ /* C type -> QObject */
+ mo = qmp_output_visitor_new();
+ v = qmp_output_get_visitor(mo);
+ visit_type_EnumOne(v, &enum1, "unused", &err);
+ if (err) {
+ g_error("%s", error_get_pretty(err));
+ }
+ obj = qmp_output_get_qobject(mo);
+ g_assert(obj);
+ str = qobject_to_json_pretty(obj);
+ g_print("%s\n", qstring_get_str(str));
+ QDECREF(str);
+ g_assert(qint_get_int(qobject_to_qint(obj)) == ENUM_ONE_VALUE1);
+
+ /* QObject -> C type */
+ mi = qmp_input_visitor_new(obj);
+ v = qmp_input_get_visitor(mi);
+ visit_type_EnumOne(v, &enum1_cpy, "unused", &err);
+ if (err) {
+ g_error("%s", error_get_pretty(err));
+ }
+ g_assert(enum1_cpy == enum1);
+
+ qobject_decref(obj);
+}
+
+/* test enum values nested in schema-defined structs */
+static void test_nested_enums(void)
+{
+ QmpOutputVisitor *mo;
+ QmpInputVisitor *mi;
+ Visitor *v;
+ NestedEnumsOne *nested_enums, *nested_enums_cpy = NULL;
+ Error *err = NULL;
+ QObject *obj;
+ QString *str;
+
+ nested_enums = qemu_mallocz(sizeof(NestedEnumsOne));
+ nested_enums->enum1 = ENUM_ONE_VALUE1;
+ nested_enums->enum2 = ENUM_ONE_VALUE2;
+ nested_enums->enum3 = ENUM_ONE_VALUE3;
+ nested_enums->enum4 = ENUM_ONE_VALUE3;
+ nested_enums->has_enum2 = false;
+ nested_enums->has_enum4 = true;
+
+ /* C type -> QObject */
+ mo = qmp_output_visitor_new();
+ v = qmp_output_get_visitor(mo);
+ visit_type_NestedEnumsOne(v, &nested_enums, NULL, &err);
+ if (err) {
+ g_error("%s", error_get_pretty(err));
+ }
+ obj = qmp_output_get_qobject(mo);
+ g_assert(obj);
+ str = qobject_to_json_pretty(obj);
+ g_print("%s\n", qstring_get_str(str));
+ QDECREF(str);
+
+ /* QObject -> C type */
+ mi = qmp_input_visitor_new(obj);
+ v = qmp_input_get_visitor(mi);
+ visit_type_NestedEnumsOne(v, &nested_enums_cpy, NULL, &err);
+ if (err) {
+ g_error("%s", error_get_pretty(err));
+ }
+ g_assert(nested_enums_cpy);
+ g_assert(nested_enums_cpy->enum1 == nested_enums->enum1);
+ g_assert(nested_enums_cpy->enum3 == nested_enums->enum3);
+ g_assert(nested_enums_cpy->enum4 == nested_enums->enum4);
+ g_assert(nested_enums_cpy->has_enum2 == false);
+ g_assert(nested_enums_cpy->has_enum4 == true);
+
+ qobject_decref(obj);
+ qapi_free_NestedEnumsOne(nested_enums);
+ qapi_free_NestedEnumsOne(nested_enums_cpy);
+}
+
+int main(int argc, char **argv)
+{
+ g_test_init(&argc, &argv, NULL);
+
+ g_test_add_func("/0.15/visitor_core", test_visitor_core);
+ g_test_add_func("/0.15/nested_structs", test_nested_structs);
+ g_test_add_func("/0.15/enums", test_enums);
+ g_test_add_func("/0.15/nested_enums", test_nested_enums);
+
+ g_test_run();
+
+ return 0;
+}
--
1.7.0.4
^ permalink raw reply related [flat|nested] 37+ messages in thread
* [Qemu-devel] [PATCH v3 17/21] qapi: configure, Fix build issue when using seperate build dir
2011-06-14 2:31 [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v3 Michael Roth
` (15 preceding siblings ...)
2011-06-14 2:31 ` [Qemu-devel] [PATCH v3 16/21] qapi: add test-visitor, tests for gen. visitor code Michael Roth
@ 2011-06-14 2:31 ` Michael Roth
2011-06-15 19:34 ` Luiz Capitulino
2011-06-14 2:31 ` [Qemu-devel] [PATCH v3 18/21] qapi: Makefile changes to build test-visitor Michael Roth
` (3 subsequent siblings)
20 siblings, 1 reply; 37+ messages in thread
From: Michael Roth @ 2011-06-14 2:31 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, Jes.Sorensen, agl, mdroth, lcapitulino
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
configure | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/configure b/configure
index d3a3a96..3d73780 100755
--- a/configure
+++ b/configure
@@ -3549,6 +3549,7 @@ DIRS="tests tests/cris slirp audio block net pc-bios/optionrom"
DIRS="$DIRS pc-bios/spapr-rtas"
DIRS="$DIRS roms/seabios roms/vgabios"
DIRS="$DIRS fsdev ui"
+DIRS="$DIRS qapi"
FILES="Makefile tests/Makefile"
FILES="$FILES tests/cris/Makefile tests/cris/.gdbinit"
FILES="$FILES pc-bios/optionrom/Makefile pc-bios/keymaps"
--
1.7.0.4
^ permalink raw reply related [flat|nested] 37+ messages in thread
* Re: [Qemu-devel] [PATCH v3 17/21] qapi: configure, Fix build issue when using seperate build dir
2011-06-14 2:31 ` [Qemu-devel] [PATCH v3 17/21] qapi: configure, Fix build issue when using seperate build dir Michael Roth
@ 2011-06-15 19:34 ` Luiz Capitulino
0 siblings, 0 replies; 37+ messages in thread
From: Luiz Capitulino @ 2011-06-15 19:34 UTC (permalink / raw)
To: Michael Roth; +Cc: aliguori, agl, qemu-devel, Jes.Sorensen
On Mon, 13 Jun 2011 21:31:22 -0500
Michael Roth <mdroth@linux.vnet.ibm.com> wrote:
>
> Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
As I commented before, this should be part of the first patch adding
a buildable code.
> ---
> configure | 1 +
> 1 files changed, 1 insertions(+), 0 deletions(-)
>
> diff --git a/configure b/configure
> index d3a3a96..3d73780 100755
> --- a/configure
> +++ b/configure
> @@ -3549,6 +3549,7 @@ DIRS="tests tests/cris slirp audio block net pc-bios/optionrom"
> DIRS="$DIRS pc-bios/spapr-rtas"
> DIRS="$DIRS roms/seabios roms/vgabios"
> DIRS="$DIRS fsdev ui"
> +DIRS="$DIRS qapi"
> FILES="Makefile tests/Makefile"
> FILES="$FILES tests/cris/Makefile tests/cris/.gdbinit"
> FILES="$FILES pc-bios/optionrom/Makefile pc-bios/keymaps"
^ permalink raw reply [flat|nested] 37+ messages in thread
* [Qemu-devel] [PATCH v3 18/21] qapi: Makefile changes to build test-visitor
2011-06-14 2:31 [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v3 Michael Roth
` (16 preceding siblings ...)
2011-06-14 2:31 ` [Qemu-devel] [PATCH v3 17/21] qapi: configure, Fix build issue when using seperate build dir Michael Roth
@ 2011-06-14 2:31 ` Michael Roth
2011-06-15 19:35 ` Luiz Capitulino
2011-06-14 2:31 ` [Qemu-devel] [PATCH v3 19/21] qapi: add test-qmp-commands, tests for gen. marshalling/dispatch code Michael Roth
` (2 subsequent siblings)
20 siblings, 1 reply; 37+ messages in thread
From: Michael Roth @ 2011-06-14 2:31 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, Jes.Sorensen, agl, mdroth, lcapitulino
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
Makefile | 16 +++++++++++++++-
1 files changed, 15 insertions(+), 1 deletions(-)
diff --git a/Makefile b/Makefile
index 306cd9b..6083085 100644
--- a/Makefile
+++ b/Makefile
@@ -145,6 +145,19 @@ check-qlist: check-qlist.o qlist.o qint.o $(CHECK_PROG_DEPS)
check-qfloat: check-qfloat.o qfloat.o $(CHECK_PROG_DEPS)
check-qjson: check-qjson.o qfloat.o qint.o qdict.o qstring.o qlist.o qbool.o qjson.o json-streamer.o json-lexer.o json-parser.o error.o qerror.o qemu-error.o $(CHECK_PROG_DEPS)
+qapi-dir := qapi-generated
+$(qapi-obj-y) test-visitor.o: QEMU_CFLAGS += -I $(qapi-dir)
+
+$(qapi-dir)/test-qapi-types.c: $(qapi-dir)/test-qapi-types.h
+$(qapi-dir)/test-qapi-types.h: $(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-types.py
+ $(call quiet-command,python $(SRC_PATH)/scripts/qapi-types.py -o "$(qapi-dir)" -p "test-" < $<, " GEN $@")
+$(qapi-dir)/test-qapi-visit.c: $(qapi-dir)/test-qapi-visit.h
+$(qapi-dir)/test-qapi-visit.h: $(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-visit.py
+ $(call quiet-command,python $(SRC_PATH)/scripts/qapi-visit.py -o "$(qapi-dir)" -p "test-" < $<, " GEN $@")
+
+test-visitor.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h)
+test-visitor: test-visitor.o qfloat.o qint.o qdict.o qstring.o qlist.o qbool.o $(qapi-obj-y) error.o osdep.o qemu-malloc.o $(oslib-obj-y) qjson.o json-streamer.o json-lexer.o json-parser.o qerror.o qemu-error.o qemu-tool.o $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o
+
QEMULIBS=libhw32 libhw64 libuser libdis libdis-user
clean:
@@ -152,11 +165,12 @@ clean:
rm -f config.mak op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h
rm -f qemu-options.def
rm -f *.o *.d *.a $(TOOLS) TAGS cscope.* *.pod *~ */*~
- rm -f slirp/*.o slirp/*.d audio/*.o audio/*.d block/*.o block/*.d net/*.o net/*.d fsdev/*.o fsdev/*.d ui/*.o ui/*.d
+ rm -f slirp/*.o slirp/*.d audio/*.o audio/*.d block/*.o block/*.d net/*.o net/*.d fsdev/*.o fsdev/*.d ui/*.o ui/*.d qapi/*.o qapi/*.d
rm -f qemu-img-cmds.h
rm -f trace.c trace.h trace.c-timestamp trace.h-timestamp
rm -f trace-dtrace.dtrace trace-dtrace.dtrace-timestamp
rm -f trace-dtrace.h trace-dtrace.h-timestamp
+ rm -rf $(qapi-dir)
$(MAKE) -C tests clean
for d in $(ALL_SUBDIRS) $(QEMULIBS) libcacard; do \
if test -d $$d; then $(MAKE) -C $$d $@ || exit 1; fi; \
--
1.7.0.4
^ permalink raw reply related [flat|nested] 37+ messages in thread
* Re: [Qemu-devel] [PATCH v3 18/21] qapi: Makefile changes to build test-visitor
2011-06-14 2:31 ` [Qemu-devel] [PATCH v3 18/21] qapi: Makefile changes to build test-visitor Michael Roth
@ 2011-06-15 19:35 ` Luiz Capitulino
0 siblings, 0 replies; 37+ messages in thread
From: Luiz Capitulino @ 2011-06-15 19:35 UTC (permalink / raw)
To: Michael Roth; +Cc: aliguori, agl, qemu-devel, Jes.Sorensen
On Mon, 13 Jun 2011 21:31:23 -0500
Michael Roth <mdroth@linux.vnet.ibm.com> wrote:
>
> Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
> ---
> Makefile | 16 +++++++++++++++-
> 1 files changed, 15 insertions(+), 1 deletions(-)
This should be merged with the patch adding the test-visitor code.
>
> diff --git a/Makefile b/Makefile
> index 306cd9b..6083085 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -145,6 +145,19 @@ check-qlist: check-qlist.o qlist.o qint.o $(CHECK_PROG_DEPS)
> check-qfloat: check-qfloat.o qfloat.o $(CHECK_PROG_DEPS)
> check-qjson: check-qjson.o qfloat.o qint.o qdict.o qstring.o qlist.o qbool.o qjson.o json-streamer.o json-lexer.o json-parser.o error.o qerror.o qemu-error.o $(CHECK_PROG_DEPS)
>
> +qapi-dir := qapi-generated
> +$(qapi-obj-y) test-visitor.o: QEMU_CFLAGS += -I $(qapi-dir)
> +
> +$(qapi-dir)/test-qapi-types.c: $(qapi-dir)/test-qapi-types.h
> +$(qapi-dir)/test-qapi-types.h: $(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-types.py
> + $(call quiet-command,python $(SRC_PATH)/scripts/qapi-types.py -o "$(qapi-dir)" -p "test-" < $<, " GEN $@")
> +$(qapi-dir)/test-qapi-visit.c: $(qapi-dir)/test-qapi-visit.h
> +$(qapi-dir)/test-qapi-visit.h: $(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-visit.py
> + $(call quiet-command,python $(SRC_PATH)/scripts/qapi-visit.py -o "$(qapi-dir)" -p "test-" < $<, " GEN $@")
> +
> +test-visitor.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h)
> +test-visitor: test-visitor.o qfloat.o qint.o qdict.o qstring.o qlist.o qbool.o $(qapi-obj-y) error.o osdep.o qemu-malloc.o $(oslib-obj-y) qjson.o json-streamer.o json-lexer.o json-parser.o qerror.o qemu-error.o qemu-tool.o $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o
> +
> QEMULIBS=libhw32 libhw64 libuser libdis libdis-user
>
> clean:
> @@ -152,11 +165,12 @@ clean:
> rm -f config.mak op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h
> rm -f qemu-options.def
> rm -f *.o *.d *.a $(TOOLS) TAGS cscope.* *.pod *~ */*~
> - rm -f slirp/*.o slirp/*.d audio/*.o audio/*.d block/*.o block/*.d net/*.o net/*.d fsdev/*.o fsdev/*.d ui/*.o ui/*.d
> + rm -f slirp/*.o slirp/*.d audio/*.o audio/*.d block/*.o block/*.d net/*.o net/*.d fsdev/*.o fsdev/*.d ui/*.o ui/*.d qapi/*.o qapi/*.d
> rm -f qemu-img-cmds.h
> rm -f trace.c trace.h trace.c-timestamp trace.h-timestamp
> rm -f trace-dtrace.dtrace trace-dtrace.dtrace-timestamp
> rm -f trace-dtrace.h trace-dtrace.h-timestamp
> + rm -rf $(qapi-dir)
> $(MAKE) -C tests clean
> for d in $(ALL_SUBDIRS) $(QEMULIBS) libcacard; do \
> if test -d $$d; then $(MAKE) -C $$d $@ || exit 1; fi; \
^ permalink raw reply [flat|nested] 37+ messages in thread
* [Qemu-devel] [PATCH v3 19/21] qapi: add test-qmp-commands, tests for gen. marshalling/dispatch code
2011-06-14 2:31 [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v3 Michael Roth
` (17 preceding siblings ...)
2011-06-14 2:31 ` [Qemu-devel] [PATCH v3 18/21] qapi: Makefile changes to build test-visitor Michael Roth
@ 2011-06-14 2:31 ` Michael Roth
2011-06-14 2:31 ` [Qemu-devel] [PATCH v3 20/21] qapi: Makefile changes to build test-qmp-commands Michael Roth
2011-06-14 2:31 ` [Qemu-devel] [PATCH v3 21/21] qapi: add QAPI code generation documentation Michael Roth
20 siblings, 0 replies; 37+ messages in thread
From: Michael Roth @ 2011-06-14 2:31 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, Jes.Sorensen, agl, mdroth, lcapitulino
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
test-qmp-commands.c | 113 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 113 insertions(+), 0 deletions(-)
create mode 100644 test-qmp-commands.c
diff --git a/test-qmp-commands.c b/test-qmp-commands.c
new file mode 100644
index 0000000..7752904
--- /dev/null
+++ b/test-qmp-commands.c
@@ -0,0 +1,113 @@
+#include <glib.h>
+#include "qemu-objects.h"
+#include "test-qmp-commands.h"
+#include "qapi/qmp-core.h"
+#include "module.h"
+
+void qmp_user_def_cmd(Error **errp)
+{
+}
+
+void qmp_user_def_cmd1(UserDefOne * ud1, Error **errp)
+{
+}
+
+UserDefTwo * qmp_user_def_cmd2(UserDefOne * ud1a, UserDefOne * ud1b, Error **errp)
+{
+ UserDefTwo *ret;
+ UserDefOne *ud1c = qemu_mallocz(sizeof(UserDefOne));
+ UserDefOne *ud1d = qemu_mallocz(sizeof(UserDefOne));
+
+ ud1c->string = strdup(ud1a->string);
+ ud1c->integer = ud1a->integer;
+ ud1d->string = strdup(ud1b->string);
+ ud1d->integer = ud1b->integer;
+
+ ret = qemu_mallocz(sizeof(UserDefTwo));
+ ret->string = strdup("blah1");
+ ret->dict.string = strdup("blah2");
+ ret->dict.dict.userdef = ud1c;
+ ret->dict.dict.string = strdup("blah3");
+ ret->dict.has_dict2 = true;
+ ret->dict.dict2.userdef = ud1d;
+ ret->dict.dict2.string = strdup("blah4");
+
+ return ret;
+}
+
+/* test commands with no input and no return value */
+static void test_dispatch_cmd(void)
+{
+ QDict *req = qdict_new();
+ QObject *resp;
+
+ qdict_put_obj(req, "execute", QOBJECT(qstring_from_str("user_def_cmd")));
+
+ resp = qmp_dispatch(QOBJECT(req));
+ assert(resp != NULL);
+ assert(!qdict_haskey(qobject_to_qdict(resp), "error"));
+ g_print("\nresp: %s\n", qstring_get_str(qobject_to_json(resp)));
+
+ qobject_decref(resp);
+ QDECREF(req);
+}
+
+/* test commands that return an error due to invalid parameters */
+static void test_dispatch_cmd_error(void)
+{
+ QDict *req = qdict_new();
+ QObject *resp;
+
+ qdict_put_obj(req, "execute", QOBJECT(qstring_from_str("user_def_cmd2")));
+
+ resp = qmp_dispatch(QOBJECT(req));
+ assert(resp != NULL);
+ assert(qdict_haskey(qobject_to_qdict(resp), "error"));
+ g_print("\nresp: %s\n", qstring_get_str(qobject_to_json_pretty(resp)));
+
+ qobject_decref(resp);
+ QDECREF(req);
+}
+
+/* test commands that involve both input parameters and return values */
+static void test_dispatch_cmd_io(void)
+{
+ QDict *req = qdict_new();
+ QDict *args = qdict_new();
+ QDict *ud1a = qdict_new();
+ QDict *ud1b = qdict_new();
+ QObject *resp;
+
+ qdict_put_obj(ud1a, "integer", QOBJECT(qint_from_int(42)));
+ qdict_put_obj(ud1a, "string", QOBJECT(qstring_from_str("hello")));
+ qdict_put_obj(ud1b, "integer", QOBJECT(qint_from_int(422)));
+ qdict_put_obj(ud1b, "string", QOBJECT(qstring_from_str("hello2")));
+ qdict_put_obj(args, "ud1a", QOBJECT(ud1a));
+ qdict_put_obj(args, "ud1b", QOBJECT(ud1b));
+ qdict_put_obj(req, "arguments", QOBJECT(args));
+
+ qdict_put_obj(req, "execute", QOBJECT(qstring_from_str("user_def_cmd2")));
+
+ /* TODO: put in full payload and check for errors */
+ resp = qmp_dispatch(QOBJECT(req));
+ assert(resp != NULL);
+ assert(!qdict_haskey(qobject_to_qdict(resp), "error"));
+ g_print("\nresp: %s\n", qstring_get_str(qobject_to_json_pretty(resp)));
+
+ qobject_decref(resp);
+ QDECREF(req);
+}
+
+int main(int argc, char **argv)
+{
+ g_test_init(&argc, &argv, NULL);
+
+ g_test_add_func("/0.15/dispatch_cmd", test_dispatch_cmd);
+ g_test_add_func("/0.15/dispatch_cmd_error", test_dispatch_cmd_error);
+ g_test_add_func("/0.15/dispatch_cmd_io", test_dispatch_cmd_io);
+
+ module_call_init(MODULE_INIT_QAPI);
+ g_test_run();
+
+ return 0;
+}
--
1.7.0.4
^ permalink raw reply related [flat|nested] 37+ messages in thread
* [Qemu-devel] [PATCH v3 20/21] qapi: Makefile changes to build test-qmp-commands
2011-06-14 2:31 [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v3 Michael Roth
` (18 preceding siblings ...)
2011-06-14 2:31 ` [Qemu-devel] [PATCH v3 19/21] qapi: add test-qmp-commands, tests for gen. marshalling/dispatch code Michael Roth
@ 2011-06-14 2:31 ` Michael Roth
2011-06-15 19:35 ` Luiz Capitulino
2011-06-14 2:31 ` [Qemu-devel] [PATCH v3 21/21] qapi: add QAPI code generation documentation Michael Roth
20 siblings, 1 reply; 37+ messages in thread
From: Michael Roth @ 2011-06-14 2:31 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, Jes.Sorensen, agl, mdroth, lcapitulino
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
Makefile | 8 +++++++-
1 files changed, 7 insertions(+), 1 deletions(-)
diff --git a/Makefile b/Makefile
index 6083085..6adf1a9 100644
--- a/Makefile
+++ b/Makefile
@@ -146,7 +146,7 @@ check-qfloat: check-qfloat.o qfloat.o $(CHECK_PROG_DEPS)
check-qjson: check-qjson.o qfloat.o qint.o qdict.o qstring.o qlist.o qbool.o qjson.o json-streamer.o json-lexer.o json-parser.o error.o qerror.o qemu-error.o $(CHECK_PROG_DEPS)
qapi-dir := qapi-generated
-$(qapi-obj-y) test-visitor.o: QEMU_CFLAGS += -I $(qapi-dir)
+$(qapi-obj-y) test-visitor.o test-qmp-commands.o: QEMU_CFLAGS += -I $(qapi-dir)
$(qapi-dir)/test-qapi-types.c: $(qapi-dir)/test-qapi-types.h
$(qapi-dir)/test-qapi-types.h: $(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-types.py
@@ -154,10 +154,16 @@ $(qapi-dir)/test-qapi-types.h: $(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scr
$(qapi-dir)/test-qapi-visit.c: $(qapi-dir)/test-qapi-visit.h
$(qapi-dir)/test-qapi-visit.h: $(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-visit.py
$(call quiet-command,python $(SRC_PATH)/scripts/qapi-visit.py -o "$(qapi-dir)" -p "test-" < $<, " GEN $@")
+$(qapi-dir)/test-qmp-commands.h: $(qapi-dir)/test-qmp-marshal.c
+$(qapi-dir)/test-qmp-marshal.c: $(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-commands.py
+ $(call quiet-command,python $(SRC_PATH)/scripts/qapi-commands.py -o "$(qapi-dir)" -p "test-" < $<, " GEN $@")
test-visitor.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h)
test-visitor: test-visitor.o qfloat.o qint.o qdict.o qstring.o qlist.o qbool.o $(qapi-obj-y) error.o osdep.o qemu-malloc.o $(oslib-obj-y) qjson.o json-streamer.o json-lexer.o json-parser.o qerror.o qemu-error.o qemu-tool.o $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o
+test-qmp-commands.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h test-qmp-marshal.c test-qmp-commands.h)
+test-qmp-commands: test-qmp-commands.o qfloat.o qint.o qdict.o qstring.o qlist.o qbool.o $(qapi-obj-y) error.o osdep.o qemu-malloc.o $(oslib-obj-y) qjson.o json-streamer.o json-lexer.o json-parser.o qerror.o qemu-error.o qemu-tool.o $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o $(qapi-dir)/test-qmp-marshal.o module.o
+
QEMULIBS=libhw32 libhw64 libuser libdis libdis-user
clean:
--
1.7.0.4
^ permalink raw reply related [flat|nested] 37+ messages in thread
* Re: [Qemu-devel] [PATCH v3 20/21] qapi: Makefile changes to build test-qmp-commands
2011-06-14 2:31 ` [Qemu-devel] [PATCH v3 20/21] qapi: Makefile changes to build test-qmp-commands Michael Roth
@ 2011-06-15 19:35 ` Luiz Capitulino
0 siblings, 0 replies; 37+ messages in thread
From: Luiz Capitulino @ 2011-06-15 19:35 UTC (permalink / raw)
To: Michael Roth; +Cc: aliguori, agl, qemu-devel, Jes.Sorensen
On Mon, 13 Jun 2011 21:31:25 -0500
Michael Roth <mdroth@linux.vnet.ibm.com> wrote:
>
> Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
> ---
> Makefile | 8 +++++++-
> 1 files changed, 7 insertions(+), 1 deletions(-)
Should be merged with the previous patch.
>
> diff --git a/Makefile b/Makefile
> index 6083085..6adf1a9 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -146,7 +146,7 @@ check-qfloat: check-qfloat.o qfloat.o $(CHECK_PROG_DEPS)
> check-qjson: check-qjson.o qfloat.o qint.o qdict.o qstring.o qlist.o qbool.o qjson.o json-streamer.o json-lexer.o json-parser.o error.o qerror.o qemu-error.o $(CHECK_PROG_DEPS)
>
> qapi-dir := qapi-generated
> -$(qapi-obj-y) test-visitor.o: QEMU_CFLAGS += -I $(qapi-dir)
> +$(qapi-obj-y) test-visitor.o test-qmp-commands.o: QEMU_CFLAGS += -I $(qapi-dir)
>
> $(qapi-dir)/test-qapi-types.c: $(qapi-dir)/test-qapi-types.h
> $(qapi-dir)/test-qapi-types.h: $(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-types.py
> @@ -154,10 +154,16 @@ $(qapi-dir)/test-qapi-types.h: $(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scr
> $(qapi-dir)/test-qapi-visit.c: $(qapi-dir)/test-qapi-visit.h
> $(qapi-dir)/test-qapi-visit.h: $(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-visit.py
> $(call quiet-command,python $(SRC_PATH)/scripts/qapi-visit.py -o "$(qapi-dir)" -p "test-" < $<, " GEN $@")
> +$(qapi-dir)/test-qmp-commands.h: $(qapi-dir)/test-qmp-marshal.c
> +$(qapi-dir)/test-qmp-marshal.c: $(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-commands.py
> + $(call quiet-command,python $(SRC_PATH)/scripts/qapi-commands.py -o "$(qapi-dir)" -p "test-" < $<, " GEN $@")
>
> test-visitor.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h)
> test-visitor: test-visitor.o qfloat.o qint.o qdict.o qstring.o qlist.o qbool.o $(qapi-obj-y) error.o osdep.o qemu-malloc.o $(oslib-obj-y) qjson.o json-streamer.o json-lexer.o json-parser.o qerror.o qemu-error.o qemu-tool.o $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o
>
> +test-qmp-commands.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h test-qmp-marshal.c test-qmp-commands.h)
> +test-qmp-commands: test-qmp-commands.o qfloat.o qint.o qdict.o qstring.o qlist.o qbool.o $(qapi-obj-y) error.o osdep.o qemu-malloc.o $(oslib-obj-y) qjson.o json-streamer.o json-lexer.o json-parser.o qerror.o qemu-error.o qemu-tool.o $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o $(qapi-dir)/test-qmp-marshal.o module.o
> +
> QEMULIBS=libhw32 libhw64 libuser libdis libdis-user
>
> clean:
^ permalink raw reply [flat|nested] 37+ messages in thread
* [Qemu-devel] [PATCH v3 21/21] qapi: add QAPI code generation documentation
2011-06-14 2:31 [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v3 Michael Roth
` (19 preceding siblings ...)
2011-06-14 2:31 ` [Qemu-devel] [PATCH v3 20/21] qapi: Makefile changes to build test-qmp-commands Michael Roth
@ 2011-06-14 2:31 ` Michael Roth
20 siblings, 0 replies; 37+ messages in thread
From: Michael Roth @ 2011-06-14 2:31 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, Jes.Sorensen, agl, mdroth, lcapitulino
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
docs/qapi-code-gen.txt | 316 ++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 316 insertions(+), 0 deletions(-)
create mode 100644 docs/qapi-code-gen.txt
diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt
new file mode 100644
index 0000000..b7befb5
--- /dev/null
+++ b/docs/qapi-code-gen.txt
@@ -0,0 +1,316 @@
+= How to use the QAPI code generator =
+
+* Note: as of this writing, QMP does not use QAPI. Eventually QMP
+commands will be converted to use QAPI internally. The following
+information describes QMP/QAPI as it will exist after the
+conversion.
+
+QAPI is a native C API within QEMU which provides management-level
+functionality to internal/external users. For external
+users/processes, this interface is made available by a JSON-based
+QEMU Monitor protocol that is provided by the QMP server.
+
+To map QMP-defined interfaces to the native C QAPI implementations,
+a JSON-based schema is used to define types and function
+signatures, and a set of scripts is used to generate types/signatures,
+and marshaling/dispatch code. The QEMU Guest Agent also uses these
+scripts, paired with a seperate schema, to generate
+marshaling/dispatch code for the guest agent server running in the
+guest.
+
+This document will describe how the schemas, scripts, and resulting
+code is used.
+
+
+== QMP/Guest agent schema ==
+
+This file defines the types, commands, and events used by QMP. It should
+fully describe the interface used by QMP.
+
+This file is designed to be loosely based on JSON although it's technically
+executable Python. While dictionaries are used, they are parsed as
+OrderedDicts so that ordering is preserved.
+
+There are two basic syntaxes used, type definitions and command definitions.
+
+The first syntax defines a type and is represented by a dictionary. There are
+two kinds of types that are supported: complex user-defined types, and enums.
+
+A complex type is a dictionary containing a single key who's value is a
+dictionary. This corresponds to a struct in C or an Object in JSON. An
+example of a complex type is:
+
+ { 'type': 'MyType',
+ 'data' { 'member1': 'str', 'member2': 'int', '*member3': 'str } }
+
+The use of '*' as a prefix to the name means the member is optional. Optional
+members should always be added to the end of the dictionary to preserve
+backwards compatibility.
+
+An enumeration type is a dictionary containing a single key who's value is a
+list of strings. An example enumeration is:
+
+ { 'enum': 'MyEnum', 'data': [ 'value1', 'value2', 'value3' ] }
+
+Generally speaking, complex types and enums should always use CamelCase for
+the type names.
+
+Commands are defined by using a list containing three members. The first
+member is the command name, the second member is a dictionary containing
+arguments, and the third member is the return type.
+
+An example command is:
+
+ { 'command': 'my-command',
+ 'data': { 'arg1': 'str', '*arg2': 'str' },
+ 'returns': 'str' ]
+
+Command names should be all lower case with words separated by a hyphen.
+
+
+== Code generation ==
+
+Schemas are fed into 3 scripts to generate all the code/files that, paired
+with the core QAPI libraries, comprise everything required to take JSON
+commands read in by a QMP/guest agent server, unmarshal the arguments into
+the underlying C types, call into the corresponding C function, and map the
+response back to a QMP/guest agent response to be returned to the user.
+
+As an example, we'll use the following schema, which describes a single
+complex user-defined type (which will produce a C struct, along with a list
+node structure that can be used to chain together a list of such types in
+case we want to accept/return a list of this type with a command), and a
+command which takes that type as a parameter and returns the same type:
+
+ mdroth@illuin:~/w/qemu2.git$ cat example-schema.json
+ { 'type': 'UserDefOne',
+ 'data': { 'integer': 'int', 'string': 'str' } }
+
+ { 'command': 'my-command',
+ 'data': {'arg1': 'UserDefOne'},
+ 'returns': 'UserDefOne' }
+ mdroth@illuin:~/w/qemu2.git$
+
+=== scripts/qapi-types.py ===
+
+Used to generate the C types defined by a schema. The following files are
+created:
+
+$(prefix)qapi-types.h - C types corresponding to types defined in
+ the schema you pass in
+$(prefix)qapi-types.c - Cleanup functions for the above C types
+
+The $(prefix) is an optional parameter used as a namespace to keep the
+generated code from one schema/code-generation separated from others so code
+can be generated/used from multiple schemas without clobbering previously
+created code.
+
+Example:
+
+ mdroth@illuin:~/w/qemu2.git$ python scripts/qapi-types.py \
+ --output-dir="qapi-generated" --prefix="example-" < example-schema.json
+ mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qapi-types.c
+ /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
+
+ #include "qapi/qapi-dealloc-visitor.h"
+ #include "example-qapi-types.h"
+ #include "example-qapi-visit.h"
+
+ void qapi_free_UserDefOne(UserDefOne * obj)
+ {
+ QapiDeallocVisitor *md;
+ Visitor *v;
+
+ if (!obj) {
+ return;
+ }
+
+ md = qapi_dealloc_visitor_new();
+ v = qapi_dealloc_get_visitor(md);
+ visit_type_UserDefOne(v, &obj, NULL, NULL);
+ qapi_dealloc_visitor_cleanup(md);
+ }
+
+ mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qapi-types.h
+ /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
+ #ifndef QAPI_GENERATED_EXAMPLE_QAPI_TYPES
+ #define QAPI_GENERATED_EXAMPLE_QAPI_TYPES
+
+ #include "qapi/qapi-types-core.h"
+
+ typedef struct UserDefOne UserDefOne;
+
+ typedef struct UserDefOneList
+ {
+ UserDefOne *value;
+ struct UserDefOneList *next;
+ } UserDefOneList;
+
+ struct UserDefOne
+ {
+ int64_t integer;
+ char * string;
+ };
+
+ void qapi_free_UserDefOne(UserDefOne * obj);
+
+ #endif
+
+
+=== scripts/qapi-visit.py ===
+
+Used to generate the visitor functions used to walk through and convert
+a QObject (as provided by QMP) to a native C data structure and
+vice-versa, as well as the visitor function used to dealloc a complex
+schema-defined C type.
+
+The following files are generated:
+
+$(prefix)qapi-visit.c: visitor function for a particular C type, used
+ to automagically convert QObjects into the
+ corresponding C type and vice-versa, as well
+ as for deallocating memory for an existing C
+ type
+
+$(prefix)qapi-visit.h: declarations for previously mentioned visitor
+ functions
+
+Example:
+
+ mdroth@illuin:~/w/qemu2.git$ python scripts/qapi-visit.py \
+ --output-dir="qapi-generated" --prefix="example-" < example-schema.json
+ mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qapi-visit.c
+ /* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
+
+ #include "example-qapi-visit.h"
+
+ void visit_type_UserDefOne(Visitor *m, UserDefOne ** obj, const char *name, Error **errp)
+ {
+ visit_start_struct(m, (void **)obj, "UserDefOne", name, sizeof(UserDefOne), errp);
+ visit_type_int(m, (obj && *obj) ? &(*obj)->integer : NULL, "integer", errp);
+ visit_type_str(m, (obj && *obj) ? &(*obj)->string : NULL, "string", errp);
+ visit_end_struct(m, errp);
+ }
+
+ void visit_type_UserDefOneList(Visitor *m, UserDefOneList ** obj, const char *name, Error **errp)
+ {
+ GenericList *i;
+
+ visit_start_list(m, name, errp);
+
+ for (i = visit_next_list(m, (GenericList **)obj, errp); i; i = visit_next_list(m, &i, errp)) {
+ UserDefOneList *native_i = (UserDefOneList *)i;
+ visit_type_UserDefOne(m, &native_i->value, NULL, errp);
+ }
+
+ visit_end_list(m, errp);
+ }
+ mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qapi-visit.h
+ /* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
+
+ #ifndef QAPI_GENERATED_EXAMPLE_QAPI_VISIT
+ #define QAPI_GENERATED_EXAMPLE_QAPI_VISIT
+
+ #include "qapi/qapi-visit-core.h"
+ #include "example-qapi-types.h"
+
+ void visit_type_UserDefOne(Visitor *m, UserDefOne ** obj, const char *name, Error **errp);
+ void visit_type_UserDefOneList(Visitor *m, UserDefOneList ** obj, const char *name, Error **errp);
+
+ #endif
+ mdroth@illuin:~/w/qemu2.git$
+
+
+=== scripts/qapi-commands.py ===
+
+Used to generate the marshaling/dispatch functions for the commands defined
+in the schema. The following files are generated:
+
+$(prefix)qmp-marshal.c: command marshal/dispatch functions for each
+ QMP command defined in the schema. Functions
+ generated by qapi-visit.py are used to
+ convert QObjects recieved from the wire into
+ function parameters, and uses the same
+ visitor functions to convert native C return
+ values to QObjects from transmission back
+ over the wire.
+
+$(prefix)qmp-commands.h: Function prototypes for the QMP commands
+ specified in the schema.
+
+Example:
+
+ mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qmp-marshal.c
+ /* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
+
+ #include "qemu-objects.h"
+ #include "qapi/qmp-core.h"
+ #include "qapi/qapi-visit-core.h"
+ #include "qapi/qmp-output-visitor.h"
+ #include "qapi/qmp-input-visitor.h"
+ #include "qapi/qapi-dealloc-visitor.h"
+ #include "example-qapi-types.h"
+ #include "example-qapi-visit.h"
+
+ #include "example-qmp-commands.h"
+ static void qmp_marshal_output_my_command(UserDefOne * ret_in, QObject **ret_out, Error **errp)
+ {
+ QapiDeallocVisitor *md = qapi_dealloc_visitor_new();
+ QmpOutputVisitor *mo = qmp_output_visitor_new();
+ Visitor *v;
+
+ v = qmp_output_get_visitor(mo);
+ visit_type_UserDefOne(v, &ret_in, "unused", errp);
+ v = qapi_dealloc_get_visitor(md);
+ visit_type_UserDefOne(v, &ret_in, "unused", errp);
+ qapi_dealloc_visitor_cleanup(md);
+
+
+ *ret_out = qmp_output_get_qobject(mo);
+ }
+
+ static void qmp_marshal_input_my_command(QmpState *qmp__sess, QDict *args, QObject **ret, Error **errp)
+ {
+ UserDefOne * retval = NULL;
+ QmpInputVisitor *mi;
+ QapiDeallocVisitor *md;
+ Visitor *v;
+ UserDefOne * arg1 = NULL;
+
+ mi = qmp_input_visitor_new(QOBJECT(args));
+ v = qmp_input_get_visitor(mi);
+ visit_type_UserDefOne(v, &arg1, "arg1", errp);
+
+ if (error_is_set(errp)) {
+ goto out;
+ }
+ retval = qmp_my_command(arg1, errp);
+ qmp_marshal_output_my_command(retval, ret, errp);
+
+ out:
+ md = qapi_dealloc_visitor_new();
+ v = qapi_dealloc_get_visitor(md);
+ visit_type_UserDefOne(v, &arg1, "arg1", errp);
+ qapi_dealloc_visitor_cleanup(md);
+ return;
+ }
+
+ static void qmp_init_marshal(void)
+ {
+ qmp_register_command("my-command", qmp_marshal_input_my_command);
+ }
+
+ qapi_init(qmp_init_marshal);
+ mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qmp-commands.h
+ /* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
+
+ #ifndef QAPI_GENERATED_EXAMPLE_QMP_COMMANDS
+ #define QAPI_GENERATED_EXAMPLE_QMP_COMMANDS
+
+ #include "example-qapi-types.h"
+ #include "error.h"
+
+ UserDefOne * qmp_my_command(UserDefOne * arg1, Error **errp);
+
+ #endif
+ mdroth@illuin:~/w/qemu2.git$
--
1.7.0.4
^ permalink raw reply related [flat|nested] 37+ messages in thread