All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v1 00/23] QAPI Infrastructure Round 1
@ 2011-05-18  0:51 Michael Roth
  2011-05-18  0:51 ` [Qemu-devel] [PATCH v1][ 01/23] Add hard build dependency on glib Michael Roth
                   ` (23 more replies)
  0 siblings, 24 replies; 36+ messages in thread
From: Michael Roth @ 2011-05-18  0:51 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, mdroth, lcapitulino

These apply on top of master, and can also be obtained from:
git://repo.or.cz/qemu/mdroth.git qapi_round1_v1

These patches are a backport of some of the QAPI-related work from Anthony's
glib tree. The main goal is to get the basic code generation infrastructure in
place so that it can be used by the guest agent to implement a QMP-like guest
interface, and so that future work regarding the QMP conversion to QAPI can be
decoupled from the infrastructure bits.

Round1 incorporates the following components from Anthony's tree:

 - Pulls in GLib libraries (core GLib, GThreads, and GIO)

 - Adds code to do exception-like error propagation

 - New error reporting functions

 - Schema-based code generation for QAPI types and synchronous QMP commands
   using visiter patterns to cut reduce the amount of code generated by the
   previous scripts. This is just infrastructure, QMP will remain untouched
   until the actual conversion efforts are underway. Only a set of unit tests
   and, in the guest, virtagent, will utilize this infrastructure initially.

The code in this patchest has been exercised fairly extensively with both the
guest agent and the unit tests, and should be fairly close to final form. Only
the qerror and glib dependencies will have any affect on the existing tree so
the hope is that continued work can be done upstream.

TESTING/USAGE:

I was planning on including generated output examples for easy reference but I
didn't want to get the patch count up too high. Reviewing that code should be be
straightforward via the unit tests however:

  For type and visiter generation: `make test-visiter`
  For type, visiter, marshalling/dispatch: `make test-qmp-commands`

Generated code will be output to $(SRC_DIR)/qapi-generated/

I'm planning on a Round2 after this which will capture a small set of patches
related to hardening the json parser. Those will potentially impact QMP
functionality so I didn't want to toss them in here.

Comments and testing are very appreciated. Thanks!

KNOWN ISSUES:

 - Extra newlines in the marshalling code
 - Memory leak in input marshalling code (input parameters need to be
   deallocated after they're passed to the QMP function)

 Makefile                    |   21 ++
 Makefile.objs               |   12 +-
 Makefile.target             |    1 +
 configure                   |   13 ++
 error.c                     |  132 +++++++++++++
 error.h                     |   70 +++++++
 error_int.h                 |   27 +++
 module.h                    |    2 +
 qapi-schema-test.json       |   16 ++
 qapi/qapi-dealloc-visiter.c |  125 ++++++++++++
 qapi/qapi-dealloc-visiter.h |   13 ++
 qapi/qapi-types-core.h      |   12 ++
 qapi/qapi-visit-core.h      |  175 +++++++++++++++++
 qapi/qmp-core.h             |   90 +++++++++
 qapi/qmp-dispatch.c         |  104 ++++++++++
 qapi/qmp-input-visiter.c    |  239 +++++++++++++++++++++++
 qapi/qmp-input-visiter.h    |   13 ++
 qapi/qmp-output-visiter.c   |  188 +++++++++++++++++++
 qapi/qmp-output-visiter.h   |   14 ++
 qapi/qmp-registry.c         |   38 ++++
 qerror-report.c             |  139 ++++++++++++++
 qerror.c                    |  178 +++++-------------
 qerror.h                    |    7 +
 qlist.h                     |   10 +
 scripts/ordereddict.py      |  128 +++++++++++++
 scripts/qapi-commands.py    |  437 +++++++++++++++++++++++++++++++++++++++++++
 scripts/qapi-types.py       |  243 ++++++++++++++++++++++++
 scripts/qapi-visit.py       |  219 ++++++++++++++++++++++
 scripts/qapi.py             |  181 ++++++++++++++++++
 test-qmp-commands.c         |  113 +++++++++++
 test-visiter.c              |  214 +++++++++++++++++++++
 31 files changed, 3045 insertions(+), 129 deletions(-)

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [Qemu-devel] [PATCH v1][ 01/23] Add hard build dependency on glib
  2011-05-18  0:51 [Qemu-devel] [PATCH v1 00/23] QAPI Infrastructure Round 1 Michael Roth
@ 2011-05-18  0:51 ` Michael Roth
  2011-05-18  0:51 ` [Qemu-devel] [PATCH v1][ 02/23] error-propagation: base code for error propagation Michael Roth
                   ` (22 subsequent siblings)
  23 siblings, 0 replies; 36+ messages in thread
From: Michael Roth @ 2011-05-18  0:51 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, Anthony Liguori, 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 2b0438c..5d39363 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 4478c61..c49e44c 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -365,3 +365,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 2e281a4..dbea7a2 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -204,6 +204,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 d7dba5d..fa95568 100755
--- a/configure
+++ b/configure
@@ -1763,6 +1763,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_softmmu"
+else
+    echo "glib-2.0 required to compile QEMU"
+    exit 1
+fi
+
+##########################################
 # kvm probe
 if test "$kvm" != "no" ; then
     cat > $TMPC <<EOF
@@ -2936,6 +2948,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] 36+ messages in thread

* [Qemu-devel] [PATCH v1][ 02/23] error-propagation: base code for error propagation
  2011-05-18  0:51 [Qemu-devel] [PATCH v1 00/23] QAPI Infrastructure Round 1 Michael Roth
  2011-05-18  0:51 ` [Qemu-devel] [PATCH v1][ 01/23] Add hard build dependency on glib Michael Roth
@ 2011-05-18  0:51 ` Michael Roth
  2011-05-18  0:51 ` [Qemu-devel] [PATCH v1][ 03/23] error-propagation: build qemu with with error-propagation bits Michael Roth
                   ` (21 subsequent siblings)
  23 siblings, 0 replies; 36+ messages in thread
From: Michael Roth @ 2011-05-18  0:51 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, mdroth, lcapitulino


Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 error.c     |  131 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 error.h     |   70 +++++++++++++++++++++++++++++++
 error_int.h |   27 ++++++++++++
 3 files changed, 228 insertions(+), 0 deletions(-)
 create mode 100644 error.c
 create mode 100644 error.h
 create mode 100644 error_int.h

diff --git a/error.c b/error.c
new file mode 100644
index 0000000..3c5a740
--- /dev/null
+++ b/error.c
@@ -0,0 +1,131 @@
+/*
+ * QEMU Error Objects
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.  See
+ * the COPYING.LIB file in the top-level directory.
+ */
+#include "error.h"
+#include "error_int.h"
+#include "qemu-objects.h"
+#include "qerror.h"
+#include <assert.h>
+
+struct Error
+{
+    QDict *obj;
+    const char *fmt;
+    char *msg;
+};
+
+void error_set(Error **errp, const char *fmt, ...)
+{
+    Error *err;
+    va_list ap;
+
+    if (errp == NULL) {
+        return;
+    }
+
+    err = qemu_mallocz(sizeof(*err));
+
+    va_start(ap, fmt);
+    err->obj = qobject_to_qdict(qobject_from_jsonv(fmt, &ap));
+    va_end(ap);
+    err->fmt = fmt;
+
+    *errp = err;
+}
+
+bool error_is_set(Error **errp)
+{
+    return (errp && *errp);
+}
+
+const char *error_get_pretty(Error *err)
+{
+    if (err->msg == NULL) {
+        QString *str;
+        str = qerror_format(err->fmt, err->obj);
+        err->msg = qemu_strdup(qstring_get_str(str));
+        QDECREF(str);
+    }
+
+    return err->msg;
+}
+
+const char *error_get_field(Error *err, const char *field)
+{
+    if (strcmp(field, "class") == 0) {
+        return qdict_get_str(err->obj, field);
+    } else {
+        QDict *dict = qdict_get_qdict(err->obj, "data");
+        return qdict_get_str(dict, field);
+    }
+}
+
+void error_set_field(Error *err, const char *field, const char *value)
+{
+    QDict *dict = qdict_get_qdict(err->obj, "data");
+    return qdict_put(dict, field, qstring_from_str(value));
+}
+
+void error_free(Error *err)
+{
+    QDECREF(err->obj);
+    qemu_free(err->msg);
+    qemu_free(err);
+}
+
+bool error_is_type(Error *err, const char *fmt)
+{
+    const char *error_class;
+    char *ptr;
+    char *end;
+
+    ptr = strstr(fmt, "'class': '");
+    assert(ptr != NULL);
+    ptr += strlen("'class': '");
+
+    end = strchr(ptr, '\'');
+    assert(end != NULL);
+
+    error_class = error_get_field(err, "class");
+    if (strlen(error_class) != end - ptr) {
+        return false;
+    }
+
+    return strncmp(ptr, error_class, end - ptr) == 0;
+}
+
+void error_propagate(Error **dst_err, Error *local_err)
+{
+    if (dst_err) {
+        *dst_err = local_err;
+    } else if (local_err) {
+        error_free(local_err);
+    }
+}
+
+QObject *error_get_qobject(Error *err)
+{
+    QINCREF(err->obj);
+    return QOBJECT(err->obj);
+}
+
+void error_set_qobject(Error **errp, QObject *obj)
+{
+    Error *err;
+    if (errp == NULL) {
+        return;
+    }
+    err = qemu_mallocz(sizeof(*err));
+    err->obj = qobject_to_qdict(obj);
+    qobject_incref(obj);
+
+    *errp = err;
+}
diff --git a/error.h b/error.h
new file mode 100644
index 0000000..003c855
--- /dev/null
+++ b/error.h
@@ -0,0 +1,70 @@
+/*
+ * QEMU Error Objects
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.  See
+ * the COPYING.LIB file in the top-level directory.
+ */
+#ifndef ERROR_H
+#define ERROR_H
+
+#include <stdbool.h>
+
+/**
+ * A class representing internal errors within QEMU.  An error has a string
+ * typename and optionally a set of named string parameters.
+ */
+typedef struct Error Error;
+
+/**
+ * Set an indirect pointer to an error given a printf-style format parameter.
+ * Currently, qerror.h defines these error formats.  This function is not
+ * meant to be used outside of QEMU.
+ */
+void error_set(Error **err, const char *fmt, ...)
+    __attribute__((format(printf, 2, 3)));
+
+/**
+ * Returns true if an indirect pointer to an error is pointing to a valid
+ * error object.
+ */
+bool error_is_set(Error **err);
+
+/**
+ * Get a human readable representation of an error object.
+ */
+const char *error_get_pretty(Error *err);
+
+/**
+ * Get an individual named error field.
+ */
+const char *error_get_field(Error *err, const char *field);
+
+/**
+ * Get an individual named error field.
+ */
+void error_set_field(Error *err, const char *field, const char *value);
+
+/**
+ * Propagate an error to an indirect pointer to an error.  This function will
+ * always transfer ownership of the error reference and handles the case where
+ * dst_err is NULL correctly.
+ */
+void error_propagate(Error **dst_err, Error *local_err);
+
+/**
+ * Free an error object.
+ */
+void error_free(Error *err);
+
+/**
+ * Determine if an error is of a speific type (based on the qerror format).
+ * Non-QEMU users should get the `class' field to identify the error type.
+ */
+bool error_is_type(Error *err, const char *fmt);
+
+#endif
diff --git a/error_int.h b/error_int.h
new file mode 100644
index 0000000..eaba65e
--- /dev/null
+++ b/error_int.h
@@ -0,0 +1,27 @@
+/*
+ * QEMU Error Objects
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.  See
+ * the COPYING.LIB file in the top-level directory.
+ */
+#ifndef QEMU_ERROR_INT_H
+#define QEMU_ERROR_INT_H
+
+#include "qemu-common.h"
+#include "qobject.h"
+#include "error.h"
+
+/**
+ * Internal QEMU functions for working with Error.
+ *
+ * These are used to convert QErrors to Errors
+ */
+QObject *error_get_qobject(Error *err);
+void error_set_qobject(Error **errp, QObject *obj);
+  
+#endif
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [Qemu-devel] [PATCH v1][ 03/23] error-propagation: build qemu with with error-propagation bits
  2011-05-18  0:51 [Qemu-devel] [PATCH v1 00/23] QAPI Infrastructure Round 1 Michael Roth
  2011-05-18  0:51 ` [Qemu-devel] [PATCH v1][ 01/23] Add hard build dependency on glib Michael Roth
  2011-05-18  0:51 ` [Qemu-devel] [PATCH v1][ 02/23] error-propagation: base code for error propagation Michael Roth
@ 2011-05-18  0:51 ` Michael Roth
  2011-05-18 13:53   ` Luiz Capitulino
  2011-05-18  0:51 ` [Qemu-devel] [PATCH v1][ 04/23] qerror: refactor error to make the human message reusable Michael Roth
                   ` (20 subsequent siblings)
  23 siblings, 1 reply; 36+ messages in thread
From: Michael Roth @ 2011-05-18  0:51 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, mdroth, lcapitulino


Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 Makefile.objs |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/Makefile.objs b/Makefile.objs
index c49e44c..0803297 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -15,6 +15,7 @@ oslib-obj-$(CONFIG_POSIX) += oslib-posix.o qemu-thread-posix.o
 
 block-obj-y = cutils.o cache-utils.o qemu-malloc.o qemu-option.o module.o async.o
 block-obj-y += nbd.o block.o aio.o aes.o qemu-config.o qemu-progress.o qemu-sockets.o
+block-obj-y += error.o
 block-obj-$(CONFIG_POSIX) += posix-aio-compat.o
 block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
 
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [Qemu-devel] [PATCH v1][ 04/23] qerror: refactor error to make the human message reusable
  2011-05-18  0:51 [Qemu-devel] [PATCH v1 00/23] QAPI Infrastructure Round 1 Michael Roth
                   ` (2 preceding siblings ...)
  2011-05-18  0:51 ` [Qemu-devel] [PATCH v1][ 03/23] error-propagation: build qemu with with error-propagation bits Michael Roth
@ 2011-05-18  0:51 ` Michael Roth
  2011-05-18  8:09   ` Stefan Hajnoczi
  2011-05-18  0:51 ` [Qemu-devel] [PATCH v1][ 05/23] qlist: add qlist_first()/qlist_next() Michael Roth
                   ` (19 subsequent siblings)
  23 siblings, 1 reply; 36+ messages in thread
From: Michael Roth @ 2011-05-18  0:51 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, Anthony Liguori, mdroth, lcapitulino

From: Anthony Liguori <aliguori@us.ibm.com>


Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 Makefile.objs   |    2 +-
 error.c         |    1 +
 qerror-report.c |  139 +++++++++++++++++++++++++++++++++++++++++++
 qerror.c        |  178 +++++++++++++++---------------------------------------
 qerror.h        |    7 ++
 5 files changed, 198 insertions(+), 129 deletions(-)
 create mode 100644 qerror-report.c

diff --git a/Makefile.objs b/Makefile.objs
index 0803297..18917c4 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -2,7 +2,7 @@
 # QObject
 qobject-obj-y = qint.o qstring.o qdict.o qlist.o qfloat.o qbool.o
 qobject-obj-y += qjson.o json-lexer.o json-streamer.o json-parser.o
-qobject-obj-y += qerror.o
+qobject-obj-y += qerror.o qerror-report.o
 
 #######################################################################
 # oslib-obj-y is code depending on the OS (win32 vs posix)
diff --git a/error.c b/error.c
index 3c5a740..ddc9105 100644
--- a/error.c
+++ b/error.c
@@ -14,6 +14,7 @@
 #include "qemu-objects.h"
 #include "qerror.h"
 #include <assert.h>
+#include <glib.h>
 
 struct Error
 {
diff --git a/qerror-report.c b/qerror-report.c
new file mode 100644
index 0000000..85773d8
--- /dev/null
+++ b/qerror-report.c
@@ -0,0 +1,139 @@
+/*
+ * QError Module
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * Authors:
+ *  Luiz Capitulino <lcapitulino@redhat.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.
+ */
+
+#include "qemu-common.h"
+#include "qerror.h"
+#include "monitor.h"
+#include "qjson.h"
+
+static void GCC_FMT_ATTR(2, 3) qerror_abort(const QError *qerr,
+                                            const char *fmt, ...)
+{
+    va_list ap;
+
+    fprintf(stderr, "qerror: bad call in function '%s':\n", qerr->func);
+    fprintf(stderr, "qerror: -> ");
+
+    va_start(ap, fmt);
+    vfprintf(stderr, fmt, ap);
+    va_end(ap);
+
+    fprintf(stderr, "\nqerror: call at %s:%d\n", qerr->file, qerr->linenr);
+    abort();
+}
+
+static void GCC_FMT_ATTR(2, 0) qerror_set_data(QError *qerr,
+                                               const char *fmt, va_list *va)
+{
+    QObject *obj;
+
+    obj = qobject_from_jsonv(fmt, va);
+    if (!obj) {
+        qerror_abort(qerr, "invalid format '%s'", fmt);
+    }
+    if (qobject_type(obj) != QTYPE_QDICT) {
+        qerror_abort(qerr, "error format is not a QDict '%s'", fmt);
+    }
+
+    qerr->error = qobject_to_qdict(obj);
+
+    obj = qdict_get(qerr->error, "class");
+    if (!obj) {
+        qerror_abort(qerr, "missing 'class' key in '%s'", fmt);
+    }
+    if (qobject_type(obj) != QTYPE_QSTRING) {
+        qerror_abort(qerr, "'class' key value should be a QString");
+    }
+
+    obj = qdict_get(qerr->error, "data");
+    if (!obj) {
+        qerror_abort(qerr, "missing 'data' key in '%s'", fmt);
+    }
+    if (qobject_type(obj) != QTYPE_QDICT) {
+        qerror_abort(qerr, "'data' key value should be a QDICT");
+    }
+}
+
+/**
+ * qerror_from_info(): Create a new QError from error information
+ *
+ * The information consists of:
+ *
+ * - file   the file name of where the error occurred
+ * - linenr the line number of where the error occurred
+ * - func   the function name of where the error occurred
+ * - fmt    JSON printf-like dictionary, there must exist keys 'class' and
+ *          'data'
+ * - va     va_list of all arguments specified by fmt
+ *
+ * Return strong reference.
+ */
+QError *qerror_from_info(const char *file, int linenr, const char *func,
+                         const char *fmt, va_list *va)
+{
+    QError *qerr;
+
+    qerr = qerror_new();
+    loc_save(&qerr->loc);
+    qerr->linenr = linenr;
+    qerr->file = file;
+    qerr->func = func;
+
+    if (!fmt) {
+        qerror_abort(qerr, "QDict not specified");
+    }
+
+    qerror_set_data(qerr, fmt, va);
+    qerror_set_desc(qerr, fmt);
+
+    return qerr;
+}
+
+/**
+ * qerror_print(): Print QError data
+ *
+ * This function will print the member 'desc' of the specified QError object,
+ * it uses error_report() for this, so that the output is routed to the right
+ * place (ie. stderr or Monitor's device).
+ */
+void qerror_print(QError *qerror)
+{
+    QString *qstring = qerror_human(qerror);
+    loc_push_restore(&qerror->loc);
+    error_report("%s", qstring_get_str(qstring));
+    loc_pop(&qerror->loc);
+    QDECREF(qstring);
+}
+
+void qerror_report_internal(const char *file, int linenr, const char *func,
+                            const char *fmt, ...)
+{
+    va_list va;
+    QError *qerror;
+
+    va_start(va, fmt);
+    qerror = qerror_from_info(file, linenr, func, fmt, &va);
+    va_end(va);
+
+    if (monitor_cur_is_qmp()) {
+        monitor_set_error(cur_mon, qerror);
+    } else {
+        qerror_print(qerror);
+        QDECREF(qerror);
+    }
+}
+
+void qerror_report_err(Error *err)
+{
+    qerror_report(QERR_UNDEFINED_ERROR);
+}
+
diff --git a/qerror.c b/qerror.c
index 4855604..49bed93 100644
--- a/qerror.c
+++ b/qerror.c
@@ -227,55 +227,17 @@ QError *qerror_new(void)
     return qerr;
 }
 
-static void GCC_FMT_ATTR(2, 3) qerror_abort(const QError *qerr,
-                                            const char *fmt, ...)
+static void parse_error(const QErrorStringTable *entry, int c)
 {
-    va_list ap;
-
-    fprintf(stderr, "qerror: bad call in function '%s':\n", qerr->func);
-    fprintf(stderr, "qerror: -> ");
-
-    va_start(ap, fmt);
-    vfprintf(stderr, fmt, ap);
-    va_end(ap);
-
-    fprintf(stderr, "\nqerror: call at %s:%d\n", qerr->file, qerr->linenr);
+#if 0
+    qerror_abort(qerror, "expected '%c' in '%s'", c, entry->desc);
+#else
+    fprintf(stderr, "expected '%c' in '%s'", c, entry->desc);
     abort();
+#endif
 }
 
-static void GCC_FMT_ATTR(2, 0) qerror_set_data(QError *qerr,
-                                               const char *fmt, va_list *va)
-{
-    QObject *obj;
-
-    obj = qobject_from_jsonv(fmt, va);
-    if (!obj) {
-        qerror_abort(qerr, "invalid format '%s'", fmt);
-    }
-    if (qobject_type(obj) != QTYPE_QDICT) {
-        qerror_abort(qerr, "error format is not a QDict '%s'", fmt);
-    }
-
-    qerr->error = qobject_to_qdict(obj);
-
-    obj = qdict_get(qerr->error, "class");
-    if (!obj) {
-        qerror_abort(qerr, "missing 'class' key in '%s'", fmt);
-    }
-    if (qobject_type(obj) != QTYPE_QSTRING) {
-        qerror_abort(qerr, "'class' key value should be a QString");
-    }
-    
-    obj = qdict_get(qerr->error, "data");
-    if (!obj) {
-        qerror_abort(qerr, "missing 'data' key in '%s'", fmt);
-    }
-    if (qobject_type(obj) != QTYPE_QDICT) {
-        qerror_abort(qerr, "'data' key value should be a QDICT");
-    }
-}
-
-static void qerror_set_desc(QError *qerr, const char *fmt)
+void qerror_set_desc(QError *qerr, const char *fmt)
 {
     int i;
 
@@ -288,50 +250,15 @@ static void qerror_set_desc(QError *qerr, const char *fmt)
         }
     }
 
+#if 0
     qerror_abort(qerr, "error format '%s' not found", fmt);
+#else
+    abort();
+#endif
 }
 
-/**
- * qerror_from_info(): Create a new QError from error information
- *
- * The information consists of:
- *
- * - file   the file name of where the error occurred
- * - linenr the line number of where the error occurred
- * - func   the function name of where the error occurred
- * - fmt    JSON printf-like dictionary, there must exist keys 'class' and
- *          'data'
- * - va     va_list of all arguments specified by fmt
- *
- * Return strong reference.
- */
-QError *qerror_from_info(const char *file, int linenr, const char *func,
-                         const char *fmt, va_list *va)
-{
-    QError *qerr;
-
-    qerr = qerror_new();
-    loc_save(&qerr->loc);
-    qerr->linenr = linenr;
-    qerr->file = file;
-    qerr->func = func;
-
-    if (!fmt) {
-        qerror_abort(qerr, "QDict not specified");
-    }
-
-    qerror_set_data(qerr, fmt, va);
-    qerror_set_desc(qerr, fmt);
-
-    return qerr;
-}
-
-static void parse_error(const QError *qerror, int c)
-{
-    qerror_abort(qerror, "expected '%c' in '%s'", c, qerror->entry->desc);
-}
-
-static const char *append_field(QString *outstr, const QError *qerror,
+static const char *append_field(QDict *error, QString *outstr,
+                                const QErrorStringTable *entry,
                                 const char *start)
 {
     QObject *obj;
@@ -340,23 +267,27 @@ static const char *append_field(QString *outstr, const QError *qerror,
     const char *end, *key;
 
     if (*start != '%')
-        parse_error(qerror, '%');
+        parse_error(entry, '%');
     start++;
     if (*start != '(')
-        parse_error(qerror, '(');
+        parse_error(entry, '(');
     start++;
 
     end = strchr(start, ')');
     if (!end)
-        parse_error(qerror, ')');
+        parse_error(entry, ')');
 
     key_qs = qstring_from_substr(start, 0, end - start - 1);
     key = qstring_get_str(key_qs);
 
-    qdict = qobject_to_qdict(qdict_get(qerror->error, "data"));
+    qdict = qobject_to_qdict(qdict_get(error, "data"));
     obj = qdict_get(qdict, key);
     if (!obj) {
+#if 0
         qerror_abort(qerror, "key '%s' not found in QDict", key);
+#else
+        abort();
+#endif
     }
 
     switch (qobject_type(obj)) {
@@ -367,73 +298,64 @@ static const char *append_field(QString *outstr, const QError *qerror,
             qstring_append_int(outstr, qdict_get_int(qdict, key));
             break;
         default:
+#if 0
             qerror_abort(qerror, "invalid type '%c'", qobject_type(obj));
+#else
+            abort();
+#endif
     }
 
     QDECREF(key_qs);
     return ++end;
 }
 
-/**
- * qerror_human(): Format QError data into human-readable string.
- *
- * Formats according to member 'desc' of the specified QError object.
- */
-QString *qerror_human(const QError *qerror)
+static QString *qerror_format_desc(QDict *error,
+                                   const QErrorStringTable *entry)
 {
-    const char *p;
     QString *qstring;
+    const char *p;
 
-    assert(qerror->entry != NULL);
+    assert(entry != NULL);
 
     qstring = qstring_new();
 
-    for (p = qerror->entry->desc; *p != '\0';) {
+    for (p = entry->desc; *p != '\0';) {
         if (*p != '%') {
             qstring_append_chr(qstring, *p++);
         } else if (*(p + 1) == '%') {
             qstring_append_chr(qstring, '%');
             p += 2;
         } else {
-            p = append_field(qstring, qerror, p);
+            p = append_field(error, qstring, entry, p);
         }
     }
 
     return qstring;
 }
 
-/**
- * qerror_print(): Print QError data
- *
- * This function will print the member 'desc' of the specified QError object,
- * it uses error_report() for this, so that the output is routed to the right
- * place (ie. stderr or Monitor's device).
- */
-void qerror_print(QError *qerror)
+QString *qerror_format(const char *fmt, QDict *error)
 {
-    QString *qstring = qerror_human(qerror);
-    loc_push_restore(&qerror->loc);
-    error_report("%s", qstring_get_str(qstring));
-    loc_pop(&qerror->loc);
-    QDECREF(qstring);
+    const QErrorStringTable *entry = NULL;
+    int i;
+
+    for (i = 0; qerror_table[i].error_fmt; i++) {
+        if (strcmp(qerror_table[i].error_fmt, fmt) == 0) {
+            entry = &qerror_table[i];
+            break;
+        }
+    }
+
+    return qerror_format_desc(error, entry);
 }
 
-void qerror_report_internal(const char *file, int linenr, const char *func,
-                            const char *fmt, ...)
+/**
+ * qerror_human(): Format QError data into human-readable string.
+ *
+ * Formats according to member 'desc' of the specified QError object.
+ */
+QString *qerror_human(const QError *qerror)
 {
-    va_list va;
-    QError *qerror;
-
-    va_start(va, fmt);
-    qerror = qerror_from_info(file, linenr, func, fmt, &va);
-    va_end(va);
-
-    if (monitor_cur_is_qmp()) {
-        monitor_set_error(cur_mon, qerror);
-    } else {
-        qerror_print(qerror);
-        QDECREF(qerror);
-    }
+    return qerror_format_desc(qerror->error, qerror->entry);
 }
 
 /**
diff --git a/qerror.h b/qerror.h
index df61d2c..09ad7dc 100644
--- a/qerror.h
+++ b/qerror.h
@@ -16,6 +16,7 @@
 #include "qstring.h"
 #include "qemu-error.h"
 #include <stdarg.h>
+#include "error.h"
 
 typedef struct QErrorStringTable {
     const char *desc;
@@ -41,7 +42,10 @@ void qerror_report_internal(const char *file, int linenr, const char *func,
                             const char *fmt, ...) GCC_FMT_ATTR(4, 5);
 #define qerror_report(fmt, ...) \
     qerror_report_internal(__FILE__, __LINE__, __func__, fmt, ## __VA_ARGS__)
+void qerror_report_err(Error *err);
 QError *qobject_to_qerror(const QObject *obj);
+QString *qerror_format(const char *fmt, QDict *error);
+void qerror_set_desc(QError *qerr, const char *fmt);
 
 /*
  * QError class list
@@ -120,6 +124,9 @@ QError *qobject_to_qerror(const QObject *obj);
 #define QERR_JSON_PARSING \
     "{ 'class': 'JSONParsing', 'data': {} }"
 
+#define QERR_JSON_PARSE_ERROR \
+        "{ 'class': 'JSONParseError', 'data': { 'message': %s } }"
+
 #define QERR_KVM_MISSING_CAP \
     "{ 'class': 'KVMMissingCap', 'data': { 'capability': %s, 'feature': %s } }"
 
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [Qemu-devel] [PATCH v1][ 05/23] qlist: add qlist_first()/qlist_next()
  2011-05-18  0:51 [Qemu-devel] [PATCH v1 00/23] QAPI Infrastructure Round 1 Michael Roth
                   ` (3 preceding siblings ...)
  2011-05-18  0:51 ` [Qemu-devel] [PATCH v1][ 04/23] qerror: refactor error to make the human message reusable Michael Roth
@ 2011-05-18  0:51 ` Michael Roth
  2011-05-18  8:12   ` Stefan Hajnoczi
  2011-05-18  0:51 ` [Qemu-devel] [PATCH v1][ 06/23] qapi: add module init types for qapi Michael Roth
                   ` (18 subsequent siblings)
  23 siblings, 1 reply; 36+ messages in thread
From: Michael Roth @ 2011-05-18  0:51 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, mdroth, lcapitulino


Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 qlist.h |   10 ++++++++++
 1 files changed, 10 insertions(+), 0 deletions(-)

diff --git a/qlist.h b/qlist.h
index dbe7b92..13f22eb 100644
--- a/qlist.h
+++ b/qlist.h
@@ -50,4 +50,14 @@ QObject *qlist_peek(QList *qlist);
 int qlist_empty(const QList *qlist);
 QList *qobject_to_qlist(const QObject *obj);
 
+static inline QListEntry *qlist_first(QList *qlist)
+{
+    return qlist->head.tqh_first;
+}
+
+static inline QListEntry *qlist_next(QListEntry *entry)
+{
+    return entry->next.tqe_next;
+}
+
 #endif /* QLIST_H */
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [Qemu-devel] [PATCH v1][ 06/23] qapi: add module init types for qapi
  2011-05-18  0:51 [Qemu-devel] [PATCH v1 00/23] QAPI Infrastructure Round 1 Michael Roth
                   ` (4 preceding siblings ...)
  2011-05-18  0:51 ` [Qemu-devel] [PATCH v1][ 05/23] qlist: add qlist_first()/qlist_next() Michael Roth
@ 2011-05-18  0:51 ` Michael Roth
  2011-05-18  0:51 ` [Qemu-devel] [PATCH v1][ 07/23] qapi: add ordereddict/qapi.py helper libraries Michael Roth
                   ` (17 subsequent siblings)
  23 siblings, 0 replies; 36+ messages in thread
From: Michael Roth @ 2011-05-18  0:51 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, 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] 36+ messages in thread

* [Qemu-devel] [PATCH v1][ 07/23] qapi: add ordereddict/qapi.py helper libraries
  2011-05-18  0:51 [Qemu-devel] [PATCH v1 00/23] QAPI Infrastructure Round 1 Michael Roth
                   ` (5 preceding siblings ...)
  2011-05-18  0:51 ` [Qemu-devel] [PATCH v1][ 06/23] qapi: add module init types for qapi Michael Roth
@ 2011-05-18  0:51 ` Michael Roth
  2011-05-18  0:51 ` [Qemu-devel] [PATCH v1][ 08/23] qapi: add qapi-types.py code generator Michael Roth
                   ` (16 subsequent siblings)
  23 siblings, 0 replies; 36+ messages in thread
From: Michael Roth @ 2011-05-18  0:51 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, mdroth, lcapitulino


Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 scripts/ordereddict.py |  128 ++++++++++++++++++++++++++++++++++
 scripts/qapi.py        |  181 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 309 insertions(+), 0 deletions(-)
 create mode 100644 scripts/ordereddict.py
 create mode 100644 scripts/qapi.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
+
diff --git a/scripts/qapi.py b/scripts/qapi.py
new file mode 100644
index 0000000..c83da32
--- /dev/null
+++ b/scripts/qapi.py
@@ -0,0 +1,181 @@
+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 = ''
+
+    for line in fp:
+        if line.startswith('#') or line == '\n':
+            continue
+
+        if line.startswith(' '):
+            expr += line
+        elif expr:
+            exprs.append(evaluate(expr))
+            expr = line
+        else:
+            expr += line
+
+    if expr:
+        exprs.append(evaluate(expr))
+
+    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():
+    global indent_level
+    indent_level += 4
+
+def pop_indent():
+    global indent_level
+    indent_level -= 4
+
+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] 36+ messages in thread

* [Qemu-devel] [PATCH v1][ 08/23] qapi: add qapi-types.py code generator
  2011-05-18  0:51 [Qemu-devel] [PATCH v1 00/23] QAPI Infrastructure Round 1 Michael Roth
                   ` (6 preceding siblings ...)
  2011-05-18  0:51 ` [Qemu-devel] [PATCH v1][ 07/23] qapi: add ordereddict/qapi.py helper libraries Michael Roth
@ 2011-05-18  0:51 ` Michael Roth
  2011-05-18  0:51 ` [Qemu-devel] [PATCH v1][ 09/23] qapi: add qapi-visit.py " Michael Roth
                   ` (15 subsequent siblings)
  23 siblings, 0 replies; 36+ messages in thread
From: Michael Roth @ 2011-05-18  0:51 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, 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 |  243 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 243 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..3bc5f95
--- /dev/null
+++ b/scripts/qapi-types.py
@@ -0,0 +1,243 @@
+from ordereddict import OrderedDict
+from qapi import *
+import sys
+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_event(name, args=[]):
+    arglist = "void *opaque"
+    for argname, argtype, optional, structured in parse_args(args):
+        if optional:
+            arglist += "bool has_%s, " % c_var(argname)
+        arglist += ", %s %s" % (c_type(argtype), c_var(argname))
+
+    ret = mcgen('''
+typedef void (%(func_type)s)(%(func_args)s);
+
+typedef struct %(struct_name)s {
+    QmpSignal *signal;
+    %(func_type)s *func;
+} %(struct_name)s;
+''',
+                func_type=camel_case("%s_func" % name),
+                func_args=arglist,
+                struct_name=camel_case("%s_event" % name))
+
+    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)
+{
+    QapiDeallocVisiter *md;
+    Visiter *v;
+
+    if (!obj) {
+        return;
+    }
+
+    md = qapi_dealloc_visiter_new();
+    v = qapi_dealloc_get_visiter(md);
+    visit_type_%(type)s(v, &obj, NULL, NULL);
+    qapi_dealloc_visiter_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
+
+fdef = open(c_file, 'w')
+fdecl = open(h_file, 'w')
+
+fdef.write(mcgen('''
+/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
+
+#include "qapi/qapi-dealloc-visiter.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'):
+        add_enum(expr['enum'])
+        ret += generate_enum(expr['enum'], expr['data'])
+    elif expr.has_key('union'):
+        add_enum('%sKind' % expr['union'])
+        ret += generate_fwd_struct(expr['union'], expr['data']) + "\n"
+        ret += generate_enum('%sKind' % expr['union'], expr['data'].keys())
+    elif expr.has_key('event'):
+        if expr.has_key('data'):
+            ret += generate_event(expr['event'], expr['data'])
+        else:
+            ret += generate_event(expr['event'])
+    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] 36+ messages in thread

* [Qemu-devel] [PATCH v1][ 09/23] qapi: add qapi-visit.py code generator
  2011-05-18  0:51 [Qemu-devel] [PATCH v1 00/23] QAPI Infrastructure Round 1 Michael Roth
                   ` (7 preceding siblings ...)
  2011-05-18  0:51 ` [Qemu-devel] [PATCH v1][ 08/23] qapi: add qapi-types.py code generator Michael Roth
@ 2011-05-18  0:51 ` Michael Roth
  2011-05-18  0:51 ` [Qemu-devel] [PATCH v1][ 10/23] qapi: add qapi-commands.py " Michael Roth
                   ` (14 subsequent siblings)
  23 siblings, 0 replies; 36+ messages in thread
From: Michael Roth @ 2011-05-18  0:51 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, 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-types.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-types.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 |  219 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 219 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..8ad6586
--- /dev/null
+++ b/scripts/qapi-visit.py
@@ -0,0 +1,219 @@
+from ordereddict import OrderedDict
+from qapi import *
+import sys
+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)->%(c_prefix)shas_%(c_name)s, "%(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", 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)->%(c_prefix)s%(c_name)s, "%(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(Visiter *m, %(name)s ** obj, const char *name, Error **errp)
+{
+    visit_start_struct(m, (void **)obj, "%(name)s", name, 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(Visiter *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(Visiter *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(Visiter *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(Visiter *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(Visiter *m, %(name)s ** obj, const char *name, Error **errp);
+''',
+                name=name)
+
+    if genlist:
+        ret += mcgen('''
+void visit_type_%(name)sList(Visiter *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(Visiter *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
+
+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] 36+ messages in thread

* [Qemu-devel] [PATCH v1][ 10/23] qapi: add qapi-commands.py code generator
  2011-05-18  0:51 [Qemu-devel] [PATCH v1 00/23] QAPI Infrastructure Round 1 Michael Roth
                   ` (8 preceding siblings ...)
  2011-05-18  0:51 ` [Qemu-devel] [PATCH v1][ 09/23] qapi: add qapi-visit.py " Michael Roth
@ 2011-05-18  0:51 ` Michael Roth
  2011-05-18  0:51 ` [Qemu-devel] [PATCH v1][ 11/23] qapi: add qapi-types-core.h Michael Roth
                   ` (13 subsequent siblings)
  23 siblings, 0 replies; 36+ messages in thread
From: Michael Roth @ 2011-05-18  0:51 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, 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 |  437 ++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 437 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..0cbe3cb
--- /dev/null
+++ b/scripts/qapi-commands.py
@@ -0,0 +1,437 @@
+from ordereddict import OrderedDict
+from qapi import *
+import sys
+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)->%(c_prefix)shas_%(c_name)s, "%(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", 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)->%(c_prefix)s%(c_name)s, "%(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(Visiter *m, %(name)s ** obj, const char *name, Error **errp)
+{
+    visit_start_struct(m, (void **)obj, "%(name)s", name, 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(Visiter *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(Visiter *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(Visiter *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(Visiter *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(Visiter *m, %(name)s ** obj, const char *name, Error **errp);
+''',
+                name=name)
+
+    if genlist:
+        ret += mcgen('''
+void visit_type_%(name)sList(Visiter *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(Visiter *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, has_ret):
+    arglist=""
+    retval=""
+    if has_ret:
+        retval = "retval = "
+    for argname, argtype, optional, structured in parse_args(args):
+        if optional:
+            arglist += "has_%s, " % c_var(argname)
+        arglist += "%s, " % (c_var(argname))
+    return mcgen('''
+%(retval)sqmp_%(name)s(%(args)serrp);
+''',
+                 name=c_var(name), args=arglist, retval=retval).rstrip()
+
+def gen_marshal_output_call(name, ret_type):
+    if not ret_type:
+        return ""
+    return mcgen('''
+qmp_marshal_output_%(c_name)s(retval, ret, errp);
+''',
+                 c_name=c_var(name))
+
+def gen_visiter_block(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))
+        ret += mcgen('''
+%(argtype)s %(argname)s;
+''',
+                      argname=c_var(argname), argtype=c_type(argtype))
+    ret += "\n"
+
+    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);
+''')
+    pop_indent()
+    return ret
+
+def gen_marshal_output(name, args, ret_type):
+    if not ret_type:
+        return ""
+    visit = ""
+    push_indent()
+    visit = mcgen('''
+QmpOutputVisiter *mo = qmp_output_visiter_new();
+Visiter *v = qmp_output_get_visiter(mo);
+
+visit_type_%(ret_type)s(v, &ret_in, "unused", errp);
+''',
+                  c_ret_type=c_type(ret_type), c_name=c_var(name),
+                  ret_type=ret_type)
+    pop_indent()
+    ret = mcgen('''
+static void qmp_marshal_output_%(c_name)s(%(c_ret_type)s ret_in, QObject **ret_out, Error **errp)
+{
+%(visit)s
+    *ret_out = qmp_output_get_qobject(mo);
+}
+''',
+            c_name=c_var(name), c_ret_type=c_type(ret_type), visit=visit)
+
+    return ret
+
+def gen_marshal_input(name, args, ret_type):
+    retval = ""
+    if ret_type:
+        retval = "    %s retval;" % c_type(ret_type)
+
+
+    ret = mcgen('''
+static void qmp_marshal_input_%(c_name)s(QmpState *qmp__sess, QDict *args, QObject **ret, Error **errp)
+{
+''',
+                c_name=c_var(name))
+
+    if (len(args) > 0):
+        ret += mcgen('''
+    QmpInputVisiter *mi = qmp_input_visiter_new(QOBJECT(args));
+    Visiter *v = qmp_input_get_visiter(mi);
+''')
+
+    ret += mcgen('''
+%(retval)s
+%(visiter_block)s
+    if (!error_is_set(errp)) {
+        %(sync_call)s
+        %(marshal_response_call)s
+    }
+}
+''',
+                 retval=retval,
+                 visiter_block=gen_visiter_block(args),
+                 sync_call=gen_sync_call(name, args, ret_type),
+                 marshal_response_call=gen_marshal_output_call(name, ret_type))
+    return ret
+
+def gen_marshal_input_proxy(name, args, ret_type):
+    retval = ""
+    if (ret_type):
+        retval = "    %s retval;" % c_type(ret_type)
+
+    ret = mcgen('''
+static void qmp_marshal_input_%(c_name)s(QmpCommandState *s, QDict *args, Error **errp)
+{
+    QmpInputVisiter *mi = qmp_input_visiter_new(QOBJECT(args));
+    Visiter *v = qmp_input_get_visiter(mi);
+%(retval)s
+%(visiter_block)s
+    qmp_proxy_dispatch(%(name)s, args, errp, s);
+''',
+                c_name=c_var(name), retval=retval,
+                visiter_block=gen_visiter_block(args), name=name)
+
+    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_registry_proxy(commands):
+    registry=""
+    push_indent()
+    for cmd in commands:
+        registry += mcgen('''
+qmp_register_proxy_command("%(name)s", qmp_marshal_input_%(c_name)s, qmp_proxy_completion_%(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"
+//#include "%(header)s"
+
+''',
+                 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-visiter.h"
+#include "qapi/qmp-input-visiter.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
+
+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()
+
+elif dispatch_type == "proxy":
+    fdef = open(c_file, 'w')
+    ret = gen_command_def_prologue(prefix=prefix, proxy=True)
+    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 = gen_marshal_input_proxy(cmd['command'], arglist, ret_type) + "\n"
+        fdef.write(ret)
+    ret = gen_registry_proxy(commands)
+    fdef.write(ret)
+
+    fdef.flush()
+    fdef.close()
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [Qemu-devel] [PATCH v1][ 11/23] qapi: add qapi-types-core.h
  2011-05-18  0:51 [Qemu-devel] [PATCH v1 00/23] QAPI Infrastructure Round 1 Michael Roth
                   ` (9 preceding siblings ...)
  2011-05-18  0:51 ` [Qemu-devel] [PATCH v1][ 10/23] qapi: add qapi-commands.py " Michael Roth
@ 2011-05-18  0:51 ` Michael Roth
  2011-05-18  0:51 ` [Qemu-devel] [PATCH v1][ 12/23] qapi: add qapi-visit-core.h Michael Roth
                   ` (12 subsequent siblings)
  23 siblings, 0 replies; 36+ messages in thread
From: Michael Roth @ 2011-05-18  0:51 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, mdroth, lcapitulino

Base declarations and includes for qapi types generator.

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 qapi/qapi-types-core.h |   12 ++++++++++++
 1 files changed, 12 insertions(+), 0 deletions(-)
 create mode 100644 qapi/qapi-types-core.h

diff --git a/qapi/qapi-types-core.h b/qapi/qapi-types-core.h
new file mode 100644
index 0000000..506a8c9
--- /dev/null
+++ b/qapi/qapi-types-core.h
@@ -0,0 +1,12 @@
+#ifndef QAPI_TYPES_CORE_H
+#define QAPI_TYPES_CORE_H
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "error.h"
+
+typedef struct QmpSignal QmpSignal;
+typedef struct QmpCommandState QmpCommandState;
+typedef struct QmpState QmpState;
+
+#endif
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [Qemu-devel] [PATCH v1][ 12/23] qapi: add qapi-visit-core.h
  2011-05-18  0:51 [Qemu-devel] [PATCH v1 00/23] QAPI Infrastructure Round 1 Michael Roth
                   ` (10 preceding siblings ...)
  2011-05-18  0:51 ` [Qemu-devel] [PATCH v1][ 11/23] qapi: add qapi-types-core.h Michael Roth
@ 2011-05-18  0:51 ` Michael Roth
  2011-05-18  0:52 ` [Qemu-devel] [PATCH v1][ 13/23] qapi: add QMP input visiter Michael Roth
                   ` (11 subsequent siblings)
  23 siblings, 0 replies; 36+ messages in thread
From: Michael Roth @ 2011-05-18  0:51 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, mdroth, lcapitulino

Base definitions/includes for Visiter interface used by generated
visiter/marshalling code.

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 qapi/qapi-visit-core.h |  175 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 175 insertions(+), 0 deletions(-)
 create mode 100644 qapi/qapi-visit-core.h

diff --git a/qapi/qapi-visit-core.h b/qapi/qapi-visit-core.h
new file mode 100644
index 0000000..c88a244
--- /dev/null
+++ b/qapi/qapi-visit-core.h
@@ -0,0 +1,175 @@
+#ifndef QAPI_VISITER_CORE_H
+#define QAPI_VISITER_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 Visiter Visiter;
+
+struct Visiter
+{
+    /* Must be set */
+    void (*start_struct)(Visiter *v, void **obj, const char *kind, const char *name, Error **errp);
+    void (*end_struct)(Visiter *v, Error **errp);
+
+    void (*start_list)(Visiter *v, const char *name, Error **errp);
+    GenericList *(*next_list)(Visiter *v, GenericList **list, Error **errp);
+    void (*end_list)(Visiter *v, Error **errp);
+
+    void (*type_enum)(Visiter *v, int *obj, const char *kind, const char *name, Error **errp);
+
+    void (*type_int)(Visiter *v, int64_t *obj, const char *name, Error **errp);
+    void (*type_bool)(Visiter *v, bool *obj, const char *name, Error **errp);
+    void (*type_str)(Visiter *v, char **obj, const char *name, Error **errp);
+    void (*type_number)(Visiter *v, double *obj, const char *name, Error **errp);
+
+    /* May be NULL */
+    void (*start_optional)(Visiter *v, bool *present, const char *name, Error **errp);
+    void (*end_optional)(Visiter *v, Error **errp);
+
+    void (*start_handle)(Visiter *v, void **obj, const char *kind, const char *name, Error **errp);
+    void (*end_handle)(Visiter *v, Error **errp);
+};
+
+static inline void visit_start_handle(Visiter *v, void **obj, const char *kind, const char *name, Error **errp)
+{
+    if (error_is_set(errp)) {
+        return;
+    }
+
+    if (v->start_handle) {
+        v->start_handle(v, obj, kind, name, errp);
+    }
+}
+
+static inline void visit_end_handle(Visiter *v, Error **errp)
+{
+    if (error_is_set(errp)) {
+        return;
+    }
+
+    if (v->end_handle) {
+        v->end_handle(v, errp);
+    }
+}
+
+static inline void visit_start_struct(Visiter *v, void **obj, const char *kind, const char *name, Error **errp)
+{
+    if (error_is_set(errp)) {
+        return;
+    }
+
+    v->start_struct(v, obj, kind, name, errp);
+}
+
+static inline void visit_end_struct(Visiter *v, Error **errp)
+{
+    if (error_is_set(errp)) {
+        return;
+    }
+
+    v->end_struct(v, errp);
+}
+
+static inline void visit_start_list(Visiter *v, const char *name, Error **errp)
+{
+    if (error_is_set(errp)) {
+        return;
+    }
+
+    v->start_list(v, name, errp);
+}
+
+static inline GenericList *visit_next_list(Visiter *v, GenericList **list, Error **errp)
+{
+    if (error_is_set(errp)) {
+        return 0;
+    }
+
+    return v->next_list(v, list, errp);
+}
+
+static inline void visit_end_list(Visiter *v, Error **errp)
+{
+    if (error_is_set(errp)) {
+        return;
+    }
+
+    v->end_list(v, errp);
+}
+
+static inline void visit_start_optional(Visiter *v, bool *present, const char *name, Error **errp)
+{
+    if (error_is_set(errp)) {
+        return;
+    }
+
+    if (v->start_optional) {
+        v->start_optional(v, present, name, errp);
+    }
+}
+
+static inline void visit_end_optional(Visiter *v, Error **errp)
+{
+    if (error_is_set(errp)) {
+        return;
+    }
+
+    if (v->end_optional) {
+        v->end_optional(v, errp);
+    }
+}
+
+static inline void visit_type_enum(Visiter *v, int *obj, const char *kind, const char *name, Error **errp)
+{
+    if (error_is_set(errp)) {
+        return;
+    }
+
+    v->type_enum(v, obj, kind, name, errp);
+}
+
+static inline void visit_type_int(Visiter *v, int64_t *obj, const char *name, Error **errp)
+{
+    if (error_is_set(errp)) {
+        return;
+    }
+
+    v->type_int(v, obj, name, errp);
+}
+
+static inline void visit_type_bool(Visiter *v, bool *obj, const char *name, Error **errp)
+{
+    if (error_is_set(errp)) {
+        return;
+    }
+
+    v->type_bool(v, obj, name, errp);
+}
+
+static inline void visit_type_str(Visiter *v, char **obj, const char *name, Error **errp)
+{
+    if (error_is_set(errp)) {
+        return;
+    }
+
+    v->type_str(v, obj, name, errp);
+}
+
+static inline void visit_type_number(Visiter *v, double *obj, const char *name, Error **errp)
+{
+    if (error_is_set(errp)) {
+        return;
+    }
+
+    v->type_number(v, obj, name, errp);
+}
+
+#endif
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [Qemu-devel] [PATCH v1][ 13/23] qapi: add QMP input visiter
  2011-05-18  0:51 [Qemu-devel] [PATCH v1 00/23] QAPI Infrastructure Round 1 Michael Roth
                   ` (11 preceding siblings ...)
  2011-05-18  0:51 ` [Qemu-devel] [PATCH v1][ 12/23] qapi: add qapi-visit-core.h Michael Roth
@ 2011-05-18  0:52 ` Michael Roth
  2011-05-18  8:35   ` Stefan Hajnoczi
  2011-05-18  0:52 ` [Qemu-devel] [PATCH v1][ 14/23] qapi: add QMP output visiter Michael Roth
                   ` (10 subsequent siblings)
  23 siblings, 1 reply; 36+ messages in thread
From: Michael Roth @ 2011-05-18  0:52 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, 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>
---
 qapi/qmp-input-visiter.c |  239 ++++++++++++++++++++++++++++++++++++++++++++++
 qapi/qmp-input-visiter.h |   13 +++
 2 files changed, 252 insertions(+), 0 deletions(-)
 create mode 100644 qapi/qmp-input-visiter.c
 create mode 100644 qapi/qmp-input-visiter.h

diff --git a/qapi/qmp-input-visiter.c b/qapi/qmp-input-visiter.c
new file mode 100644
index 0000000..6767e39
--- /dev/null
+++ b/qapi/qmp-input-visiter.c
@@ -0,0 +1,239 @@
+#include "qmp-input-visiter.h"
+#include "qemu-queue.h"
+#include "qemu-common.h"
+#include "qemu-objects.h"
+#include "qerror.h"
+
+#define QAPI_OBJECT_SIZE 512
+
+#define QIV_STACK_SIZE 1024
+
+typedef struct StackObject
+{
+    QObject *obj;
+    QListEntry *entry;
+} StackObject;
+
+struct QmpInputVisiter
+{
+    Visiter visiter;
+    QObject *obj;
+    StackObject stack[QIV_STACK_SIZE];
+    int nb_stack;
+};
+
+static QmpInputVisiter *to_qiv(Visiter *v)
+{
+    return container_of(v, QmpInputVisiter, visiter);
+}
+
+static QObject *qmp_input_get_object(QmpInputVisiter *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(QmpInputVisiter *qiv, QObject *obj)
+{
+    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++;
+
+    assert(qiv->nb_stack < QIV_STACK_SIZE); // FIXME
+}
+
+static void qmp_input_pop(QmpInputVisiter *qiv)
+{
+    qiv->nb_stack--;
+    assert(qiv->nb_stack >= 0); // FIXME
+}
+
+static void qmp_input_start_struct(Visiter *v, void **obj, const char *kind, const char *name, Error **errp)
+{
+    QmpInputVisiter *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, "object");
+        return;
+    }
+
+    qmp_input_push(qiv, qobj);
+
+    if (obj) {
+        *obj = qemu_mallocz(QAPI_OBJECT_SIZE);
+    }
+}
+
+static void qmp_input_end_struct(Visiter *v, Error **errp)
+{
+    QmpInputVisiter *qiv = to_qiv(v);
+
+    qmp_input_pop(qiv);
+}
+
+static void qmp_input_start_list(Visiter *v, const char *name, Error **errp)
+{
+    QmpInputVisiter *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, "list");
+        return;
+    }
+
+    qmp_input_push(qiv, qobj);
+}
+
+static GenericList *qmp_input_next_list(Visiter *v, GenericList **list, Error **errp)
+{
+    QmpInputVisiter *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(Visiter *v, Error **errp)
+{
+    QmpInputVisiter *qiv = to_qiv(v);
+
+    qmp_input_pop(qiv);
+}
+
+static void qmp_input_type_int(Visiter *v, int64_t *obj, const char *name, Error **errp)
+{
+    QmpInputVisiter *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, "integer");
+        return;
+    }
+
+    *obj = qint_get_int(qobject_to_qint(qobj));
+}
+
+static void qmp_input_type_bool(Visiter *v, bool *obj, const char *name, Error **errp)
+{
+    QmpInputVisiter *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, "boolean");
+        return;
+    }
+
+    *obj = qbool_get_int(qobject_to_qbool(qobj));
+}
+
+static void qmp_input_type_str(Visiter *v, char **obj, const char *name, Error **errp)
+{
+    QmpInputVisiter *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, "string");
+        return;
+    }
+
+    *obj = qemu_strdup(qstring_get_str(qobject_to_qstring(qobj)));
+}
+
+static void qmp_input_type_number(Visiter *v, double *obj, const char *name, Error **errp)
+{
+    QmpInputVisiter *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, "double");
+        return;
+    }
+
+    *obj = qfloat_get_double(qobject_to_qfloat(qobj));
+}
+
+static void qmp_input_type_enum(Visiter *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(Visiter *v, bool *present,
+                                     const char *name, Error **errp)
+{
+    QmpInputVisiter *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(Visiter *v, Error **errp)
+{
+}
+
+Visiter *qmp_input_get_visiter(QmpInputVisiter *v)
+{
+    return &v->visiter;
+}
+
+QmpInputVisiter *qmp_input_visiter_new(QObject *obj)
+{
+    QmpInputVisiter *v;
+
+    v = qemu_mallocz(sizeof(*v));
+
+    v->visiter.start_struct = qmp_input_start_struct;
+    v->visiter.end_struct = qmp_input_end_struct;
+    v->visiter.start_list = qmp_input_start_list;
+    v->visiter.next_list = qmp_input_next_list;
+    v->visiter.end_list = qmp_input_end_list;
+    v->visiter.type_enum = qmp_input_type_enum;
+    v->visiter.type_int = qmp_input_type_int;
+    v->visiter.type_bool = qmp_input_type_bool;
+    v->visiter.type_str = qmp_input_type_str;
+    v->visiter.type_number = qmp_input_type_number;
+    v->visiter.start_optional = qmp_input_start_optional;
+    v->visiter.end_optional = qmp_input_end_optional;
+
+    v->obj = obj;
+
+    return v;
+}
diff --git a/qapi/qmp-input-visiter.h b/qapi/qmp-input-visiter.h
new file mode 100644
index 0000000..71eb380
--- /dev/null
+++ b/qapi/qmp-input-visiter.h
@@ -0,0 +1,13 @@
+#ifndef QMP_INPUT_VISITER_H
+#define QMP_INPUT_VISITER_H
+
+#include "qapi-visit-core.h"
+#include "qobject.h"
+
+typedef struct QmpInputVisiter QmpInputVisiter;
+
+QmpInputVisiter *qmp_input_visiter_new(QObject *obj);
+
+Visiter *qmp_input_get_visiter(QmpInputVisiter *v);
+
+#endif
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [Qemu-devel] [PATCH v1][ 14/23] qapi: add QMP output visiter
  2011-05-18  0:51 [Qemu-devel] [PATCH v1 00/23] QAPI Infrastructure Round 1 Michael Roth
                   ` (12 preceding siblings ...)
  2011-05-18  0:52 ` [Qemu-devel] [PATCH v1][ 13/23] qapi: add QMP input visiter Michael Roth
@ 2011-05-18  0:52 ` Michael Roth
  2011-05-18  8:44   ` Stefan Hajnoczi
  2011-05-18  0:52 ` [Qemu-devel] [PATCH v1][ 15/23] qapi: add QAPI dealloc visiter Michael Roth
                   ` (9 subsequent siblings)
  23 siblings, 1 reply; 36+ messages in thread
From: Michael Roth @ 2011-05-18  0:52 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, mdroth, lcapitulino

Type of Visiter class that serves as the inverse of the input visiter:
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>
---
 qapi/qmp-output-visiter.c |  188 +++++++++++++++++++++++++++++++++++++++++++++
 qapi/qmp-output-visiter.h |   14 ++++
 2 files changed, 202 insertions(+), 0 deletions(-)
 create mode 100644 qapi/qmp-output-visiter.c
 create mode 100644 qapi/qmp-output-visiter.h

diff --git a/qapi/qmp-output-visiter.c b/qapi/qmp-output-visiter.c
new file mode 100644
index 0000000..c8c03c0
--- /dev/null
+++ b/qapi/qmp-output-visiter.c
@@ -0,0 +1,188 @@
+#include "qmp-output-visiter.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 QmpOutputVisiter
+{
+    Visiter visiter;
+    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 QmpOutputVisiter *to_qov(Visiter *v)
+{
+    return container_of(v, QmpOutputVisiter, visiter);
+}
+
+static void qmp_output_push_obj(QmpOutputVisiter *qov, QObject *value)
+{
+    QStackEntry *e = qemu_mallocz(sizeof(*e));
+
+    e->value = value;
+    QTAILQ_INSERT_HEAD(&qov->stack, e, node);
+}
+
+static QObject *qmp_output_pop(QmpOutputVisiter *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(QmpOutputVisiter *qov)
+{
+    QStackEntry *e = QTAILQ_LAST(&qov->stack, QStack);
+    return e->value;
+}
+
+static QObject *qmp_output_last(QmpOutputVisiter *qov)
+{
+    QStackEntry *e = QTAILQ_FIRST(&qov->stack);
+    return e->value;
+}
+
+static void qmp_output_add_obj(QmpOutputVisiter *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(Visiter *v, void **obj, const char *kind, const char *name, Error **errp)
+{
+    QmpOutputVisiter *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(Visiter *v, Error **errp)
+{
+    QmpOutputVisiter *qov = to_qov(v);
+    qmp_output_pop(qov);
+}
+
+static void qmp_output_start_list(Visiter *v, const char *name, Error **errp)
+{
+    QmpOutputVisiter *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(Visiter *v, GenericList **list, Error **errp)
+{
+    GenericList *retval = *list;
+    *list = retval->next;
+    return retval;
+}
+
+static void qmp_output_end_list(Visiter *v, Error **errp)
+{
+    QmpOutputVisiter *qov = to_qov(v);
+    qmp_output_pop(qov);
+}
+
+static void qmp_output_type_int(Visiter *v, int64_t *obj, const char *name, Error **errp)
+{
+    QmpOutputVisiter *qov = to_qov(v);
+    qmp_output_add(qov, name, qint_from_int(*obj));
+}
+
+static void qmp_output_type_bool(Visiter *v, bool *obj, const char *name, Error **errp)
+{
+    QmpOutputVisiter *qov = to_qov(v);
+    qmp_output_add(qov, name, qbool_from_int(*obj));
+}
+
+static void qmp_output_type_str(Visiter *v, char **obj, const char *name, Error **errp)
+{
+    QmpOutputVisiter *qov = to_qov(v);
+    qmp_output_add(qov, name, qstring_from_str(*obj));
+}
+
+static void qmp_output_type_number(Visiter *v, double *obj, const char *name, Error **errp)
+{
+    QmpOutputVisiter *qov = to_qov(v);
+    qmp_output_add(qov, name, qfloat_from_double(*obj));
+}
+
+#if 0
+static void qmp_output_type_enum(Visiter *v, int *obj, const char *kind, const char *name, Error **errp)
+{
+    QmpOutputVisiter *qov = to_qov(v);
+    qmp_output_add(qov, name, qstring_from_str(qapi_enum_int2str(*obj)));
+}
+#else
+static void qmp_output_type_enum(Visiter *v, int *obj, const char *kind, const char *name, Error **errp)
+{
+    int64_t value = *obj;
+    qmp_output_type_int(v, &value, name, errp);
+}
+#endif
+
+QObject *qmp_output_get_qobject(QmpOutputVisiter *qov)
+{
+    return qmp_output_first(qov);
+}
+
+Visiter *qmp_output_get_visiter(QmpOutputVisiter *v)
+{
+    return &v->visiter;
+}
+
+QmpOutputVisiter *qmp_output_visiter_new(void)
+{
+    QmpOutputVisiter *v;
+
+    v = qemu_mallocz(sizeof(*v));
+
+    v->visiter.start_struct = qmp_output_start_struct;
+    v->visiter.end_struct = qmp_output_end_struct;
+    v->visiter.start_list = qmp_output_start_list;
+    v->visiter.next_list = qmp_output_next_list;
+    v->visiter.end_list = qmp_output_end_list;
+    v->visiter.type_enum = qmp_output_type_enum;
+    v->visiter.type_int = qmp_output_type_int;
+    v->visiter.type_bool = qmp_output_type_bool;
+    v->visiter.type_str = qmp_output_type_str;
+    v->visiter.type_number = qmp_output_type_number;
+
+    QTAILQ_INIT(&v->stack);
+
+    return v;
+}
diff --git a/qapi/qmp-output-visiter.h b/qapi/qmp-output-visiter.h
new file mode 100644
index 0000000..f4904cb
--- /dev/null
+++ b/qapi/qmp-output-visiter.h
@@ -0,0 +1,14 @@
+#ifndef QMP_OUTPUT_VISITER_H
+#define QMP_OUTPUT_VISITER_H
+
+#include "qapi-visit-core.h"
+#include "qobject.h"
+
+typedef struct QmpOutputVisiter QmpOutputVisiter;
+
+QmpOutputVisiter *qmp_output_visiter_new(void);
+
+QObject *qmp_output_get_qobject(QmpOutputVisiter *v);
+Visiter *qmp_output_get_visiter(QmpOutputVisiter *v);
+
+#endif
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [Qemu-devel] [PATCH v1][ 15/23] qapi: add QAPI dealloc visiter
  2011-05-18  0:51 [Qemu-devel] [PATCH v1 00/23] QAPI Infrastructure Round 1 Michael Roth
                   ` (13 preceding siblings ...)
  2011-05-18  0:52 ` [Qemu-devel] [PATCH v1][ 14/23] qapi: add QMP output visiter Michael Roth
@ 2011-05-18  0:52 ` Michael Roth
  2011-05-18  0:52 ` [Qemu-devel] [PATCH v1][ 16/23] qapi: add command registration/lookup functions Michael Roth
                   ` (8 subsequent siblings)
  23 siblings, 0 replies; 36+ messages in thread
From: Michael Roth @ 2011-05-18  0:52 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, mdroth, lcapitulino

Type of Visiter class that can be passed into a qapi-generated C
type's visiter function to free() any heap-allocated data types.

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 qapi/qapi-dealloc-visiter.c |  125 +++++++++++++++++++++++++++++++++++++++++++
 qapi/qapi-dealloc-visiter.h |   13 +++++
 2 files changed, 138 insertions(+), 0 deletions(-)
 create mode 100644 qapi/qapi-dealloc-visiter.c
 create mode 100644 qapi/qapi-dealloc-visiter.h

diff --git a/qapi/qapi-dealloc-visiter.c b/qapi/qapi-dealloc-visiter.c
new file mode 100644
index 0000000..3c669cc
--- /dev/null
+++ b/qapi/qapi-dealloc-visiter.c
@@ -0,0 +1,125 @@
+#include "qapi-dealloc-visiter.h"
+#include "qemu-queue.h"
+#include "qemu-common.h"
+#include "qemu-objects.h"
+
+typedef struct StackEntry
+{
+    void *value;
+    QTAILQ_ENTRY(StackEntry) node;
+} StackEntry;
+
+struct QapiDeallocVisiter
+{
+    Visiter visiter;
+    QTAILQ_HEAD(, StackEntry) stack;
+};
+
+static QapiDeallocVisiter *to_qov(Visiter *v)
+{
+    return container_of(v, QapiDeallocVisiter, visiter);
+}
+
+static void qapi_dealloc_push(QapiDeallocVisiter *qov, void *value)
+{
+    StackEntry *e = qemu_mallocz(sizeof(*e));
+
+    e->value = value;
+    QTAILQ_INSERT_HEAD(&qov->stack, e, node);
+}
+
+static void *qapi_dealloc_pop(QapiDeallocVisiter *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(Visiter *v, void **obj, const char *kind, const char *name, Error **errp)
+{
+    QapiDeallocVisiter *qov = to_qov(v);
+    qapi_dealloc_push(qov, obj);
+}
+
+static void qapi_dealloc_end_struct(Visiter *v, Error **errp)
+{
+    QapiDeallocVisiter *qov = to_qov(v);
+    void **obj = qapi_dealloc_pop(qov);
+    if (obj && *obj) {
+        qemu_free(*obj);
+    }
+}
+
+static void qapi_dealloc_start_list(Visiter *v, const char *name, Error **errp)
+{
+}
+
+static GenericList *qapi_dealloc_next_list(Visiter *v, GenericList **list, Error **errp)
+{
+    GenericList *retval = *list;
+    assert(retval->value);
+    qemu_free(retval->value);
+    *list = retval->next;
+    return retval;
+}
+
+static void qapi_dealloc_end_list(Visiter *v, Error **errp)
+{
+}
+
+static void qapi_dealloc_type_str(Visiter *v, char **obj, const char *name, Error **errp)
+{
+    assert(obj && *obj);
+    qemu_free(*obj);
+}
+
+static void qapi_dealloc_type_int(Visiter *v, int64_t *obj, const char *name, Error **errp)
+{
+}
+
+static void qapi_dealloc_type_bool(Visiter *v, bool *obj, const char *name, Error **errp)
+{
+}
+
+static void qapi_dealloc_type_number(Visiter *v, double *obj, const char *name, Error **errp)
+{
+}
+
+static void qapi_dealloc_type_enum(Visiter *v, int *obj, const char *kind, const char *name, Error **errp)
+{
+}
+
+Visiter *qapi_dealloc_get_visiter(QapiDeallocVisiter *v)
+{
+    return &v->visiter;
+}
+
+void qapi_dealloc_visiter_cleanup(QapiDeallocVisiter *v)
+{
+    qemu_free(v);
+}
+
+QapiDeallocVisiter *qapi_dealloc_visiter_new(void)
+{
+    QapiDeallocVisiter *v;
+
+    v = qemu_mallocz(sizeof(*v));
+
+    v->visiter.start_struct = qapi_dealloc_start_struct;
+    v->visiter.end_struct = qapi_dealloc_end_struct;
+    v->visiter.start_list = qapi_dealloc_start_list;
+    v->visiter.next_list = qapi_dealloc_next_list;
+    v->visiter.end_list = qapi_dealloc_end_list;
+    v->visiter.type_enum = qapi_dealloc_type_enum;
+    v->visiter.type_int = qapi_dealloc_type_int;
+    v->visiter.type_bool = qapi_dealloc_type_bool;
+    v->visiter.type_str = qapi_dealloc_type_str;
+    v->visiter.type_number = qapi_dealloc_type_number;
+
+    QTAILQ_INIT(&v->stack);
+
+    return v;
+}
diff --git a/qapi/qapi-dealloc-visiter.h b/qapi/qapi-dealloc-visiter.h
new file mode 100644
index 0000000..df1fa20
--- /dev/null
+++ b/qapi/qapi-dealloc-visiter.h
@@ -0,0 +1,13 @@
+#ifndef QAPI_DEALLOC_VISITER_H
+#define QAPI_DEALLOC_VISITER_H
+
+#include "qapi-visit-core.h"
+
+typedef struct QapiDeallocVisiter QapiDeallocVisiter;
+
+QapiDeallocVisiter *qapi_dealloc_visiter_new(void);
+void qapi_dealloc_visiter_cleanup(QapiDeallocVisiter *d);
+
+Visiter *qapi_dealloc_get_visiter(QapiDeallocVisiter *v);
+
+#endif
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [Qemu-devel] [PATCH v1][ 16/23] qapi: add command registration/lookup functions
  2011-05-18  0:51 [Qemu-devel] [PATCH v1 00/23] QAPI Infrastructure Round 1 Michael Roth
                   ` (14 preceding siblings ...)
  2011-05-18  0:52 ` [Qemu-devel] [PATCH v1][ 15/23] qapi: add QAPI dealloc visiter Michael Roth
@ 2011-05-18  0:52 ` Michael Roth
  2011-05-18  0:52 ` [Qemu-devel] [PATCH v1][ 17/23] qapi: add QMP dispatch functions Michael Roth
                   ` (7 subsequent siblings)
  23 siblings, 0 replies; 36+ messages in thread
From: Michael Roth @ 2011-05-18  0:52 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, 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>
---
 qapi/qmp-registry.c |   38 ++++++++++++++++++++++++++++++++++++++
 1 files changed, 38 insertions(+), 0 deletions(-)
 create mode 100644 qapi/qmp-registry.c

diff --git a/qapi/qmp-registry.c b/qapi/qmp-registry.c
new file mode 100644
index 0000000..06811ec
--- /dev/null
+++ b/qapi/qmp-registry.c
@@ -0,0 +1,38 @@
+#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);
+}
+
+void qmp_register_proxy_command(const char *name, QmpProxyCommandFunc *fn, QmpProxyCompletionFunc *cb)
+{
+    QmpCommand *cmd = qemu_mallocz(sizeof(*cmd));
+
+    cmd->name = name;
+    cmd->type = QCT_PROXY;
+    //cmd->fn = fn;
+    cmd->pfn = 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] 36+ messages in thread

* [Qemu-devel] [PATCH v1][ 17/23] qapi: add QMP dispatch functions
  2011-05-18  0:51 [Qemu-devel] [PATCH v1 00/23] QAPI Infrastructure Round 1 Michael Roth
                   ` (15 preceding siblings ...)
  2011-05-18  0:52 ` [Qemu-devel] [PATCH v1][ 16/23] qapi: add command registration/lookup functions Michael Roth
@ 2011-05-18  0:52 ` Michael Roth
  2011-05-18  8:58   ` Stefan Hajnoczi
  2011-05-18  0:52 ` [Qemu-devel] [PATCH v1][ 18/23] qapi: add base declaration/types for QMP Michael Roth
                   ` (6 subsequent siblings)
  23 siblings, 1 reply; 36+ messages in thread
From: Michael Roth @ 2011-05-18  0:52 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, 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>
---
 qapi/qmp-dispatch.c |  104 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 104 insertions(+), 0 deletions(-)
 create mode 100644 qapi/qmp-dispatch.c

diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c
new file mode 100644
index 0000000..733decf
--- /dev/null
+++ b/qapi/qmp-dispatch.c
@@ -0,0 +1,104 @@
+#include <glib.h>
+#include "qemu-objects.h"
+#include "qapi/qmp-core.h"
+#include "json-parser.h"
+
+static QObject *qmp_dispatch_err(QmpState *state, QObject *request, Error **errp)
+{
+    const char *command;
+    QDict *args, *dict;
+    //QObject *request;
+    QmpCommand *cmd;
+    QObject *ret = NULL;
+    //Error *err = 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(state, args, &ret, errp);
+        if (ret == NULL) {
+            ret = QOBJECT(qdict_new());
+        }
+        break;
+    case QCT_ASYNC: {
+        QmpCommandState *s = qemu_mallocz(sizeof(*s));
+        // FIXME save async commands and do something
+        // smart if disconnect occurs before completion
+        s->state = state;
+        s->tag = NULL;
+        if (qdict_haskey(dict, "tag")) {
+            s->tag = qdict_get(dict, "tag");
+            qobject_incref(s->tag);
+        }
+        cmd->afn(args, errp, s);
+        ret = NULL;
+    }
+        break;
+    case QCT_PROXY: {
+        QmpCommandState *s = qemu_mallocz(sizeof(*s));
+        // FIXME save async commands and do something
+        // smart if disconnect occurs before completion
+        s->state = state;
+        s->tag = NULL;
+        if (qdict_haskey(dict, "tag")) {
+            s->tag = qdict_get(dict, "tag");
+            qobject_incref(s->tag);
+        }
+        cmd->pfn(args, errp, s);
+        ret = NULL;
+    }
+        break;
+    }
+
+    QDECREF(args);
+
+out:
+
+    return ret;
+}
+
+QObject *qmp_dispatch(QmpState *state, QObject *request)
+{
+    Error *err = NULL;
+    QObject *ret;
+    QDict *rsp;
+
+    ret = qmp_dispatch_err(state, 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] 36+ messages in thread

* [Qemu-devel] [PATCH v1][ 18/23] qapi: add base declaration/types for QMP
  2011-05-18  0:51 [Qemu-devel] [PATCH v1 00/23] QAPI Infrastructure Round 1 Michael Roth
                   ` (16 preceding siblings ...)
  2011-05-18  0:52 ` [Qemu-devel] [PATCH v1][ 17/23] qapi: add QMP dispatch functions Michael Roth
@ 2011-05-18  0:52 ` Michael Roth
  2011-05-18  0:52 ` [Qemu-devel] [PATCH v1][ 19/23] qapi: test schema used for unit tests Michael Roth
                   ` (5 subsequent siblings)
  23 siblings, 0 replies; 36+ messages in thread
From: Michael Roth @ 2011-05-18  0:52 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, mdroth, lcapitulino


Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 qapi/qmp-core.h |   90 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 90 insertions(+), 0 deletions(-)
 create mode 100644 qapi/qmp-core.h

diff --git a/qapi/qmp-core.h b/qapi/qmp-core.h
new file mode 100644
index 0000000..c4a20a8
--- /dev/null
+++ b/qapi/qmp-core.h
@@ -0,0 +1,90 @@
+#ifndef QMP_CORE_H
+#define QMP_CORE_H
+
+#include "monitor.h"
+#include "error_int.h"
+#include "qapi/qapi-types-core.h"
+
+struct QmpCommandState
+{
+    QmpState *state;
+    QObject *tag;
+};
+
+typedef struct DefaultQmpConnection
+{
+    QmpSignal *obj;
+    int handle;
+    QTAILQ_ENTRY(DefaultQmpConnection) node;
+} DefaultQmpConnection;
+
+typedef void (QmpCommandFunc)(QmpState *qmp__sess, QDict *, QObject **, Error **);
+typedef void (QmpAsyncCommandFunc)(const QDict *, Error **, QmpCommandState *);
+typedef void (QmpProxyCommandFunc)(QDict *args, Error **errp, QmpCommandState *s);
+typedef void (QmpProxyCompletionFunc)(QmpCommandState *s, QDict *ret, Error **errp);
+
+typedef enum QmpCommandType
+{
+    QCT_NORMAL,
+    QCT_ASYNC,
+    QCT_PROXY,
+} QmpCommandType;
+
+typedef struct QmpCommand
+{
+    const char *name;
+    QmpCommandType type;
+    QmpCommandFunc *fn;
+    QmpAsyncCommandFunc *afn;
+    QmpProxyCommandFunc *pfn;
+    QTAILQ_ENTRY(QmpCommand) node;
+} QmpCommand;
+
+void qmp_register_command(const char *name, QmpCommandFunc *fn);
+void qmp_register_proxy_command(const char *name, QmpProxyCommandFunc *fn, QmpProxyCompletionFunc *cb);
+QmpCommand *qmp_find_command(const char *name);
+void qmp_async_complete_command(QmpCommandState *cmd, QObject *retval, Error *err);
+
+typedef void (SignalFunc)(void);
+
+typedef struct QmpSlot
+{
+    int handle;
+    SignalFunc *func;
+    void *opaque;
+    QTAILQ_ENTRY(QmpSlot) node;
+} QmpSlot;
+
+struct QmpSignal
+{
+    int max_handle;
+    int ref;
+    QTAILQ_HEAD(, QmpSlot) slots;
+};
+
+typedef struct QmpConnection
+{
+    QmpState *state;
+    const char *event_name;
+    QmpSignal *signal;
+    int handle;
+    int global_handle;
+    QTAILQ_ENTRY(QmpConnection) node;
+} QmpConnection;
+
+struct QmpState
+{
+    int (*add_connection)(QmpState *s, QmpConnection *conn);
+    void (*del_connection)(QmpState *s, int global_handle, Error **errp);
+    void (*event)(QmpState *s, QObject *data);
+    int (*get_fd)(QmpState *s);
+
+    QTAILQ_HEAD(, DefaultQmpConnection) default_connections;
+};
+
+
+QObject *qmp_dispatch(QmpState *state, QObject *request);
+void qmp_proxy_dispatch(const char *name, QDict *args, Error **errp, QmpCommandState *s);
+
+#endif
+
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [Qemu-devel] [PATCH v1][ 19/23] qapi: test schema used for unit tests
  2011-05-18  0:51 [Qemu-devel] [PATCH v1 00/23] QAPI Infrastructure Round 1 Michael Roth
                   ` (17 preceding siblings ...)
  2011-05-18  0:52 ` [Qemu-devel] [PATCH v1][ 18/23] qapi: add base declaration/types for QMP Michael Roth
@ 2011-05-18  0:52 ` Michael Roth
  2011-05-18  0:52 ` [Qemu-devel] [PATCH v1][ 20/23] qapi: add test-visiter, tests for gen. visiter code Michael Roth
                   ` (4 subsequent siblings)
  23 siblings, 0 replies; 36+ messages in thread
From: Michael Roth @ 2011-05-18  0:52 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, 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 |   16 ++++++++++++++++
 1 files changed, 16 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..3c8d56b
--- /dev/null
+++ b/qapi-schema-test.json
@@ -0,0 +1,16 @@
+# *-*- Mode: Python -*-*
+
+# 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] 36+ messages in thread

* [Qemu-devel] [PATCH v1][ 20/23] qapi: add test-visiter, tests for gen. visiter code
  2011-05-18  0:51 [Qemu-devel] [PATCH v1 00/23] QAPI Infrastructure Round 1 Michael Roth
                   ` (18 preceding siblings ...)
  2011-05-18  0:52 ` [Qemu-devel] [PATCH v1][ 19/23] qapi: test schema used for unit tests Michael Roth
@ 2011-05-18  0:52 ` Michael Roth
  2011-05-18  0:52 ` [Qemu-devel] [PATCH v1][ 21/23] qapi: Makefile changes to build test-visiter Michael Roth
                   ` (3 subsequent siblings)
  23 siblings, 0 replies; 36+ messages in thread
From: Michael Roth @ 2011-05-18  0:52 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, mdroth, lcapitulino


Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 test-visiter.c |  214 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 214 insertions(+), 0 deletions(-)
 create mode 100644 test-visiter.c

diff --git a/test-visiter.c b/test-visiter.c
new file mode 100644
index 0000000..31596a0
--- /dev/null
+++ b/test-visiter.c
@@ -0,0 +1,214 @@
+#include <glib.h>
+#include "qapi/qmp-output-visiter.h"
+#include "qapi/qmp-input-visiter.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(Visiter *v, TestStruct **obj, const char *name, Error **errp)
+{
+    visit_start_struct(v, (void **)obj, "TestStruct", name, 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(Visiter *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 deep nesting with refs to other user-defined types */
+static void test_nested_structs(void)
+{
+    QmpOutputVisiter *mo;
+    QmpInputVisiter *mi;
+    Visiter *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_visiter_new();
+    v = qmp_output_get_visiter(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_visiter_new();
+    v = qmp_output_get_visiter(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_visiter_new(obj);
+    v = qmp_input_get_visiter(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);
+}
+
+int main(int argc, char **argv)
+{
+    QmpOutputVisiter *mo;
+    QmpInputVisiter *mi;
+    Visiter *v;
+    TestStruct ts = { 42, 82 };
+    TestStruct *pts = &ts;
+    TestStructList *lts = NULL;
+    Error *err = NULL;
+    QObject *obj;
+    QString *str;
+
+    g_test_init(&argc, &argv, NULL);
+
+    mo = qmp_output_visiter_new();
+    v = qmp_output_get_visiter(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_visiter_new(obj);
+    v = qmp_input_get_visiter(mi);
+
+    int64_t value = 0;
+
+    visit_type_int(v, &value, NULL, &err);
+    if (err) {
+        printf("%s\n", error_get_pretty(err));
+        return 1;
+    }
+
+    g_assert(value == 0x42);
+
+    qobject_decref(obj);
+
+    obj = qobject_from_json("{'x': 42, 'y': 84}");
+    mi = qmp_input_visiter_new(obj);
+    v = qmp_input_get_visiter(mi);
+
+    pts = NULL;
+
+    visit_type_TestStruct(v, &pts, NULL, &err);
+    if (err) {
+        printf("%s\n", error_get_pretty(err));
+        return 1;
+    }
+
+    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_visiter_new(obj);
+    v = qmp_input_get_visiter(mi);
+
+    visit_type_TestStructList(v, &lts, NULL, &err);
+    if (err) {
+        printf("%s\n", error_get_pretty(err));
+        return 1;
+    }
+
+    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);
+
+    g_test_add_func("/0.15/nested_structs", test_nested_structs);
+
+    g_test_run();
+
+    return 0;
+}
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [Qemu-devel] [PATCH v1][ 21/23] qapi: Makefile changes to build test-visiter
  2011-05-18  0:51 [Qemu-devel] [PATCH v1 00/23] QAPI Infrastructure Round 1 Michael Roth
                   ` (19 preceding siblings ...)
  2011-05-18  0:52 ` [Qemu-devel] [PATCH v1][ 20/23] qapi: add test-visiter, tests for gen. visiter code Michael Roth
@ 2011-05-18  0:52 ` Michael Roth
  2011-05-18  0:52 ` [Qemu-devel] [PATCH v1][ 22/23] qapi: add test-qmp-commands, tests for gen. marshalling/dispatch code Michael Roth
                   ` (2 subsequent siblings)
  23 siblings, 0 replies; 36+ messages in thread
From: Michael Roth @ 2011-05-18  0:52 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, mdroth, lcapitulino


Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 Makefile      |   13 +++++++++++++
 Makefile.objs |    7 +++++++
 2 files changed, 20 insertions(+), 0 deletions(-)

diff --git a/Makefile b/Makefile
index 5d39363..55ae073 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 $(CHECK_PROG_DEPS)
 
+qapi-dir := qapi-generated
+$(qapi-obj-y) test-visiter.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-visiter.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h)
+test-visiter: test-visiter.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 $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o
+
 QEMULIBS=libhw32 libhw64 libuser libdis libdis-user
 
 clean:
diff --git a/Makefile.objs b/Makefile.objs
index 18917c4..0147847 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -362,6 +362,13 @@ 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 = qmp-input-visiter.o qmp-output-visiter.o qapi-dealloc-visiter.o
+qapi-nested-y += qmp-registry.o qmp-dispatch.o
+qapi-obj-y = $(addprefix qapi/, $(qapi-nested-y))
+
 vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
 
 vl.o: QEMU_CFLAGS+=$(SDL_CFLAGS)
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [Qemu-devel] [PATCH v1][ 22/23] qapi: add test-qmp-commands, tests for gen. marshalling/dispatch code
  2011-05-18  0:51 [Qemu-devel] [PATCH v1 00/23] QAPI Infrastructure Round 1 Michael Roth
                   ` (20 preceding siblings ...)
  2011-05-18  0:52 ` [Qemu-devel] [PATCH v1][ 21/23] qapi: Makefile changes to build test-visiter Michael Roth
@ 2011-05-18  0:52 ` Michael Roth
  2011-05-18  0:52 ` [Qemu-devel] [PATCH v1][ 23/23] qapi: Makefile changes to build test-qmp-commands Michael Roth
  2011-05-18 13:46 ` [Qemu-devel] [PATCH v1 00/23] QAPI Infrastructure Round 1 Luiz Capitulino
  23 siblings, 0 replies; 36+ messages in thread
From: Michael Roth @ 2011-05-18  0:52 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, 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..8cdd5c9
--- /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(NULL, 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(NULL, 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(NULL, 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] 36+ messages in thread

* [Qemu-devel] [PATCH v1][ 23/23] qapi: Makefile changes to build test-qmp-commands
  2011-05-18  0:51 [Qemu-devel] [PATCH v1 00/23] QAPI Infrastructure Round 1 Michael Roth
                   ` (21 preceding siblings ...)
  2011-05-18  0:52 ` [Qemu-devel] [PATCH v1][ 22/23] qapi: add test-qmp-commands, tests for gen. marshalling/dispatch code Michael Roth
@ 2011-05-18  0:52 ` Michael Roth
  2011-05-18 13:46 ` [Qemu-devel] [PATCH v1 00/23] QAPI Infrastructure Round 1 Luiz Capitulino
  23 siblings, 0 replies; 36+ messages in thread
From: Michael Roth @ 2011-05-18  0:52 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, 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 55ae073..39b2936 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 $(CHECK_PROG_DEPS)
 
 qapi-dir := qapi-generated
-$(qapi-obj-y) test-visiter.o: QEMU_CFLAGS += -I $(qapi-dir)
+$(qapi-obj-y) test-visiter.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-visiter.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h)
 test-visiter: test-visiter.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 $(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 $(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] 36+ messages in thread

* Re: [Qemu-devel] [PATCH v1][ 04/23] qerror: refactor error to make the human message reusable
  2011-05-18  0:51 ` [Qemu-devel] [PATCH v1][ 04/23] qerror: refactor error to make the human message reusable Michael Roth
@ 2011-05-18  8:09   ` Stefan Hajnoczi
  2011-05-18 13:54     ` Luiz Capitulino
  0 siblings, 1 reply; 36+ messages in thread
From: Stefan Hajnoczi @ 2011-05-18  8:09 UTC (permalink / raw)
  To: Michael Roth; +Cc: aliguori, Anthony Liguori, qemu-devel, lcapitulino

On Wed, May 18, 2011 at 1:51 AM, Michael Roth <mdroth@linux.vnet.ibm.com> wrote:
> +#if 0
> +    qerror_abort(qerror, "expected '%c' in '%s'", c, entry->desc);
> +#else
> +    fprintf(stderr, "expected '%c' in '%s'", c, entry->desc);
>     abort();
> +#endif

There are a couple of #if 0 in the patch, please resolve them.

Stefan

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [Qemu-devel] [PATCH v1][ 05/23] qlist: add qlist_first()/qlist_next()
  2011-05-18  0:51 ` [Qemu-devel] [PATCH v1][ 05/23] qlist: add qlist_first()/qlist_next() Michael Roth
@ 2011-05-18  8:12   ` Stefan Hajnoczi
  0 siblings, 0 replies; 36+ messages in thread
From: Stefan Hajnoczi @ 2011-05-18  8:12 UTC (permalink / raw)
  To: Michael Roth; +Cc: aliguori, qemu-devel, lcapitulino

On Wed, May 18, 2011 at 1:51 AM, Michael Roth <mdroth@linux.vnet.ibm.com> wrote:
>
> Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
> ---
>  qlist.h |   10 ++++++++++
>  1 files changed, 10 insertions(+), 0 deletions(-)
>
> diff --git a/qlist.h b/qlist.h
> index dbe7b92..13f22eb 100644
> --- a/qlist.h
> +++ b/qlist.h
> @@ -50,4 +50,14 @@ QObject *qlist_peek(QList *qlist);
>  int qlist_empty(const QList *qlist);
>  QList *qobject_to_qlist(const QObject *obj);
>
> +static inline QListEntry *qlist_first(QList *qlist)
> +{
> +    return qlist->head.tqh_first;

return QTAILQ_FIRST(&qlist->head);

> +}
> +
> +static inline QListEntry *qlist_next(QListEntry *entry)
> +{
> +    return entry->next.tqe_next;

return QTAILQ_NEXT(&entry->next);

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [Qemu-devel] [PATCH v1][ 13/23] qapi: add QMP input visiter
  2011-05-18  0:52 ` [Qemu-devel] [PATCH v1][ 13/23] qapi: add QMP input visiter Michael Roth
@ 2011-05-18  8:35   ` Stefan Hajnoczi
  0 siblings, 0 replies; 36+ messages in thread
From: Stefan Hajnoczi @ 2011-05-18  8:35 UTC (permalink / raw)
  To: Michael Roth; +Cc: aliguori, qemu-devel, lcapitulino

On Wed, May 18, 2011 at 1:52 AM, 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>
> ---
>  qapi/qmp-input-visiter.c |  239 ++++++++++++++++++++++++++++++++++++++++++++++
>  qapi/qmp-input-visiter.h |   13 +++
>  2 files changed, 252 insertions(+), 0 deletions(-)
>  create mode 100644 qapi/qmp-input-visiter.c
>  create mode 100644 qapi/qmp-input-visiter.h

Pedantic note: the design pattern is commonly spelled "visitor":
http://en.wikipedia.org/wiki/Visitor_pattern

The fixed-size stack and hardcoded object size are unfortunate but I
haven't read the code in enough detail to see if there is a feasible
alternative.

Stefan

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [Qemu-devel] [PATCH v1][ 14/23] qapi: add QMP output visiter
  2011-05-18  0:52 ` [Qemu-devel] [PATCH v1][ 14/23] qapi: add QMP output visiter Michael Roth
@ 2011-05-18  8:44   ` Stefan Hajnoczi
  0 siblings, 0 replies; 36+ messages in thread
From: Stefan Hajnoczi @ 2011-05-18  8:44 UTC (permalink / raw)
  To: Michael Roth; +Cc: aliguori, qemu-devel, lcapitulino

On Wed, May 18, 2011 at 1:52 AM, Michael Roth <mdroth@linux.vnet.ibm.com> wrote:
> Type of Visiter class that serves as the inverse of the input visiter:
> 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>
> ---
>  qapi/qmp-output-visiter.c |  188 +++++++++++++++++++++++++++++++++++++++++++++
>  qapi/qmp-output-visiter.h |   14 ++++
>  2 files changed, 202 insertions(+), 0 deletions(-)
>  create mode 100644 qapi/qmp-output-visiter.c
>  create mode 100644 qapi/qmp-output-visiter.h
>
> diff --git a/qapi/qmp-output-visiter.c b/qapi/qmp-output-visiter.c
> new file mode 100644
> index 0000000..c8c03c0
> --- /dev/null
> +++ b/qapi/qmp-output-visiter.c
> @@ -0,0 +1,188 @@

License/copyright header?

> +#if 0
> +static void qmp_output_type_enum(Visiter *v, int *obj, const char *kind, const char *name, Error **errp)
> +{
> +    QmpOutputVisiter *qov = to_qov(v);
> +    qmp_output_add(qov, name, qstring_from_str(qapi_enum_int2str(*obj)));
> +}
> +#else
> +static void qmp_output_type_enum(Visiter *v, int *obj, const char *kind, const char *name, Error **errp)
> +{
> +    int64_t value = *obj;
> +    qmp_output_type_int(v, &value, name, errp);
> +}
> +#endif

Looks like string constants were used for enums before but now plain
integers are used instead.  Please resolve the #if 0.

Stefan

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [Qemu-devel] [PATCH v1][ 17/23] qapi: add QMP dispatch functions
  2011-05-18  0:52 ` [Qemu-devel] [PATCH v1][ 17/23] qapi: add QMP dispatch functions Michael Roth
@ 2011-05-18  8:58   ` Stefan Hajnoczi
  0 siblings, 0 replies; 36+ messages in thread
From: Stefan Hajnoczi @ 2011-05-18  8:58 UTC (permalink / raw)
  To: Michael Roth; +Cc: aliguori, qemu-devel, lcapitulino

On Wed, May 18, 2011 at 1:52 AM, 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>
> ---
>  qapi/qmp-dispatch.c |  104 +++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 files changed, 104 insertions(+), 0 deletions(-)
>  create mode 100644 qapi/qmp-dispatch.c
>
> diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c
> new file mode 100644
> index 0000000..733decf
> --- /dev/null
> +++ b/qapi/qmp-dispatch.c
> @@ -0,0 +1,104 @@
> +#include <glib.h>
> +#include "qemu-objects.h"
> +#include "qapi/qmp-core.h"
> +#include "json-parser.h"
> +
> +static QObject *qmp_dispatch_err(QmpState *state, QObject *request, Error **errp)
> +{
> +    const char *command;
> +    QDict *args, *dict;
> +    //QObject *request;
> +    QmpCommand *cmd;
> +    QObject *ret = NULL;
> +    //Error *err = NULL;

Please remove commented out lines, it makes the code noisy.

> +    case QCT_ASYNC: {
> +        QmpCommandState *s = qemu_mallocz(sizeof(*s));
> +        // FIXME save async commands and do something
> +        // smart if disconnect occurs before completion
> +        s->state = state;
> +        s->tag = NULL;
> +        if (qdict_haskey(dict, "tag")) {
> +            s->tag = qdict_get(dict, "tag");
> +            qobject_incref(s->tag);
> +        }
> +        cmd->afn(args, errp, s);

async_fn() would be a clear name.

> +        ret = NULL;

It is already NULL.

> +    }
> +        break;
> +    case QCT_PROXY: {
> +        QmpCommandState *s = qemu_mallocz(sizeof(*s));
> +        // FIXME save async commands and do something
> +        // smart if disconnect occurs before completion
> +        s->state = state;
> +        s->tag = NULL;
> +        if (qdict_haskey(dict, "tag")) {
> +            s->tag = qdict_get(dict, "tag");
> +            qobject_incref(s->tag);
> +        }
> +        cmd->pfn(args, errp, s);
> +        ret = NULL;

Same comments as for async.

Stefan

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [Qemu-devel] [PATCH v1 00/23] QAPI Infrastructure Round 1
  2011-05-18  0:51 [Qemu-devel] [PATCH v1 00/23] QAPI Infrastructure Round 1 Michael Roth
                   ` (22 preceding siblings ...)
  2011-05-18  0:52 ` [Qemu-devel] [PATCH v1][ 23/23] qapi: Makefile changes to build test-qmp-commands Michael Roth
@ 2011-05-18 13:46 ` Luiz Capitulino
  2011-05-18 14:43   ` Michael Roth
  23 siblings, 1 reply; 36+ messages in thread
From: Luiz Capitulino @ 2011-05-18 13:46 UTC (permalink / raw)
  To: Michael Roth; +Cc: aliguori, qemu-devel, Markus Armbruster

On Tue, 17 May 2011 19:51:47 -0500
Michael Roth <mdroth@linux.vnet.ibm.com> wrote:

> These apply on top of master, and can also be obtained from:
> git://repo.or.cz/qemu/mdroth.git qapi_round1_v1

Nice to see this moving forward.

> These patches are a backport of some of the QAPI-related work from Anthony's
> glib tree. The main goal is to get the basic code generation infrastructure in
> place so that it can be used by the guest agent to implement a QMP-like guest
> interface, and so that future work regarding the QMP conversion to QAPI can be
> decoupled from the infrastructure bits.
> 
> Round1 incorporates the following components from Anthony's tree:
> 
>  - Pulls in GLib libraries (core GLib, GThreads, and GIO)
> 
>  - Adds code to do exception-like error propagation
> 
>  - New error reporting functions
> 
>  - Schema-based code generation for QAPI types and synchronous QMP commands
>    using visiter patterns to cut reduce the amount of code generated by the
>    previous scripts. This is just infrastructure, QMP will remain untouched
>    until the actual conversion efforts are underway. Only a set of unit tests
>    and, in the guest, virtagent, will utilize this infrastructure initially.

This series introduces quite a lot of infrastructure w/o adding a single real
user. This has some disadvantages, the most important one being that we can't
test it for real (unit-tests are important, but don't replace real usage).
Another disadvantage is that, reviewers don't actually see how this is going to
be used and can't comment on API level improvements/bugs.

I prefer an incremental approach. We could try to split this series in smaller
parts and change current QMP to use that parts. This will make review easier
and will make it possible to do incremental testing too.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [Qemu-devel] [PATCH v1][ 03/23] error-propagation: build qemu with with error-propagation bits
  2011-05-18  0:51 ` [Qemu-devel] [PATCH v1][ 03/23] error-propagation: build qemu with with error-propagation bits Michael Roth
@ 2011-05-18 13:53   ` Luiz Capitulino
  0 siblings, 0 replies; 36+ messages in thread
From: Luiz Capitulino @ 2011-05-18 13:53 UTC (permalink / raw)
  To: Michael Roth; +Cc: aliguori, qemu-devel

On Tue, 17 May 2011 19:51:50 -0500
Michael Roth <mdroth@linux.vnet.ibm.com> wrote:

> 
> Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
> ---
>  Makefile.objs |    1 +
>  1 files changed, 1 insertions(+), 0 deletions(-)
> 
> diff --git a/Makefile.objs b/Makefile.objs
> index c49e44c..0803297 100644
> --- a/Makefile.objs
> +++ b/Makefile.objs
> @@ -15,6 +15,7 @@ oslib-obj-$(CONFIG_POSIX) += oslib-posix.o qemu-thread-posix.o
>  
>  block-obj-y = cutils.o cache-utils.o qemu-malloc.o qemu-option.o module.o async.o
>  block-obj-y += nbd.o block.o aio.o aes.o qemu-config.o qemu-progress.o qemu-sockets.o
> +block-obj-y += error.o
>  block-obj-$(CONFIG_POSIX) += posix-aio-compat.o
>  block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o

This should be squashed in the previous patch, but it won't build as it
depends on a change in qerror.c. I got this problem too, but (I hope that I)
fixed it properly.

I also made two small changes and am working on unit-tests.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [Qemu-devel] [PATCH v1][ 04/23] qerror: refactor error to make the human message reusable
  2011-05-18  8:09   ` Stefan Hajnoczi
@ 2011-05-18 13:54     ` Luiz Capitulino
  0 siblings, 0 replies; 36+ messages in thread
From: Luiz Capitulino @ 2011-05-18 13:54 UTC (permalink / raw)
  To: Stefan Hajnoczi; +Cc: aliguori, Anthony Liguori, Michael Roth, qemu-devel

On Wed, 18 May 2011 09:09:28 +0100
Stefan Hajnoczi <stefanha@gmail.com> wrote:

> On Wed, May 18, 2011 at 1:51 AM, Michael Roth <mdroth@linux.vnet.ibm.com> wrote:
> > +#if 0
> > +    qerror_abort(qerror, "expected '%c' in '%s'", c, entry->desc);
> > +#else
> > +    fprintf(stderr, "expected '%c' in '%s'", c, entry->desc);
> >     abort();
> > +#endif
> 
> There are a couple of #if 0 in the patch, please resolve them.

Yes and this does more than the subject says.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [Qemu-devel] [PATCH v1 00/23] QAPI Infrastructure Round 1
  2011-05-18 13:46 ` [Qemu-devel] [PATCH v1 00/23] QAPI Infrastructure Round 1 Luiz Capitulino
@ 2011-05-18 14:43   ` Michael Roth
  2011-05-18 15:10     ` Luiz Capitulino
  0 siblings, 1 reply; 36+ messages in thread
From: Michael Roth @ 2011-05-18 14:43 UTC (permalink / raw)
  To: Luiz Capitulino; +Cc: aliguori, qemu-devel, Markus Armbruster

On 05/18/2011 08:46 AM, Luiz Capitulino wrote:
> On Tue, 17 May 2011 19:51:47 -0500
> Michael Roth<mdroth@linux.vnet.ibm.com>  wrote:
>
>> These apply on top of master, and can also be obtained from:
>> git://repo.or.cz/qemu/mdroth.git qapi_round1_v1
>
> Nice to see this moving forward.
>
>> These patches are a backport of some of the QAPI-related work from Anthony's
>> glib tree. The main goal is to get the basic code generation infrastructure in
>> place so that it can be used by the guest agent to implement a QMP-like guest
>> interface, and so that future work regarding the QMP conversion to QAPI can be
>> decoupled from the infrastructure bits.
>>
>> Round1 incorporates the following components from Anthony's tree:
>>
>>   - Pulls in GLib libraries (core GLib, GThreads, and GIO)
>>
>>   - Adds code to do exception-like error propagation
>>
>>   - New error reporting functions
>>
>>   - Schema-based code generation for QAPI types and synchronous QMP commands
>>     using visiter patterns to cut reduce the amount of code generated by the
>>     previous scripts. This is just infrastructure, QMP will remain untouched
>>     until the actual conversion efforts are underway. Only a set of unit tests
>>     and, in the guest, virtagent, will utilize this infrastructure initially.
>
> This series introduces quite a lot of infrastructure w/o adding a single real
> user. This has some disadvantages, the most important one being that we can't
> test it for real (unit-tests are important, but don't replace real usage).
> Another disadvantage is that, reviewers don't actually see how this is going to
> be used and can't comment on API level improvements/bugs.

The guest agent user will mirror the QMP user pretty closely, but I 
could see why it'd be nice to have an actual QMP user as part of the 
series. I think we decided on IRC that an incremental QMP conversion 
wouldn't be the best route and should instead be done as part of a 
single concerted effort. So one approach I would propose is to have 
example conversions tacked on to the end of this series.

So for this series we'd have 1 or 2 example conversions for synchronous 
QMP functions. Future infrastructure patches could provide examples for 
async QMP/proxied QMP/QMP event/qcfg/etc users as the relevant 
infrastructure bits are added.

So long as the example conversions capture the general use cases, we'd 
still be able to decouple conversion efforts from infrastructure (with 
any corner cases fixed as a part of those efforts), while allowing the 
infrastructure code to be reviewed in the proper context.

>
> I prefer an incremental approach. We could try to split this series in smaller
> parts and change current QMP to use that parts. This will make review easier
> and will make it possible to do incremental testing too.
>

I could split the code conversion stuff out into a separate series. So 
we'd have:

Round 1: error-related changes
Round 2: json-related changes
Round 3: code conversion infra + examples

If we take the approach mentioned above, anyway.

Otherwise I don't see how we could decouple any QMP conversion efforts 
from infrastructure (which I think was considered desirable). In terms 
of the code generation it's basically all or nothing, with the exception 
of the unit tests we've added. Did you have something else in mind?

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [Qemu-devel] [PATCH v1 00/23] QAPI Infrastructure Round 1
  2011-05-18 14:43   ` Michael Roth
@ 2011-05-18 15:10     ` Luiz Capitulino
  2011-05-18 16:33       ` Michael Roth
  0 siblings, 1 reply; 36+ messages in thread
From: Luiz Capitulino @ 2011-05-18 15:10 UTC (permalink / raw)
  To: Michael Roth; +Cc: aliguori, qemu-devel, Markus Armbruster

On Wed, 18 May 2011 09:43:37 -0500
Michael Roth <mdroth@linux.vnet.ibm.com> wrote:

> On 05/18/2011 08:46 AM, Luiz Capitulino wrote:
> > On Tue, 17 May 2011 19:51:47 -0500
> > Michael Roth<mdroth@linux.vnet.ibm.com>  wrote:
> >
> >> These apply on top of master, and can also be obtained from:
> >> git://repo.or.cz/qemu/mdroth.git qapi_round1_v1
> >
> > Nice to see this moving forward.
> >
> >> These patches are a backport of some of the QAPI-related work from Anthony's
> >> glib tree. The main goal is to get the basic code generation infrastructure in
> >> place so that it can be used by the guest agent to implement a QMP-like guest
> >> interface, and so that future work regarding the QMP conversion to QAPI can be
> >> decoupled from the infrastructure bits.
> >>
> >> Round1 incorporates the following components from Anthony's tree:
> >>
> >>   - Pulls in GLib libraries (core GLib, GThreads, and GIO)
> >>
> >>   - Adds code to do exception-like error propagation
> >>
> >>   - New error reporting functions
> >>
> >>   - Schema-based code generation for QAPI types and synchronous QMP commands
> >>     using visiter patterns to cut reduce the amount of code generated by the
> >>     previous scripts. This is just infrastructure, QMP will remain untouched
> >>     until the actual conversion efforts are underway. Only a set of unit tests
> >>     and, in the guest, virtagent, will utilize this infrastructure initially.
> >
> > This series introduces quite a lot of infrastructure w/o adding a single real
> > user. This has some disadvantages, the most important one being that we can't
> > test it for real (unit-tests are important, but don't replace real usage).
> > Another disadvantage is that, reviewers don't actually see how this is going to
> > be used and can't comment on API level improvements/bugs.
> 
> The guest agent user will mirror the QMP user pretty closely, but I 
> could see why it'd be nice to have an actual QMP user as part of the 
> series. I think we decided on IRC that an incremental QMP conversion 
> wouldn't be the best route and should instead be done as part of a 
> single concerted effort. So one approach I would propose is to have 
> example conversions tacked on to the end of this series.

Yes, that would be good.

> So for this series we'd have 1 or 2 example conversions for synchronous 
> QMP functions. Future infrastructure patches could provide examples for 
> async QMP/proxied QMP/QMP event/qcfg/etc users as the relevant 
> infrastructure bits are added.

I think the examples have to use all the added infrastructure. For example,
if you're not adding async commands, then we'd have to drop the async support
from the series.

I'm tempted to say that we should try to reduce the code generator (and all
the infrastructure around it) to generated only the bits that are going to be
used by the examples. But I'm not sure if the work involved is worth it.

> So long as the example conversions capture the general use cases, we'd 
> still be able to decouple conversion efforts from infrastructure (with 
> any corner cases fixed as a part of those efforts), while allowing the 
> infrastructure code to be reviewed in the proper context.

Yes.

> > I prefer an incremental approach. We could try to split this series in smaller
> > parts and change current QMP to use that parts. This will make review easier
> > and will make it possible to do incremental testing too.
> >
> 
> I could split the code conversion stuff out into a separate series. So 
> we'd have:

Looks good to me.

> Round 1: error-related changes

I'm already taking care of this one. I hope to have patches soon. The problem
here is that I'm very serious about testing and am going to test each
converted handler. Unfortunately, most of the testing is done by hand today :(
but kvm-autotest has some support for testing error paths and libvirt has a
more general suite too.

> Round 2: json-related changes

I think I saw patches flying on the list, did you submit then? Do they
depend on the error stuff?

> Round 3: code conversion infra + examples
> 
> If we take the approach mentioned above, anyway.
> 
> Otherwise I don't see how we could decouple any QMP conversion efforts 
> from infrastructure (which I think was considered desirable). In terms 
> of the code generation it's basically all or nothing, with the exception 
> of the unit tests we've added. Did you have something else in mind?

Your plan looks good to me. I mean, maybe it' me who's is still catching up
with all that stuff and want it to go slower so that I can fully absorb it
and try to make sure it won't break anything before it's merged.

On the other hand, we might want to discuss errors separately for example,
as it's not specified to QMP.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [Qemu-devel] [PATCH v1 00/23] QAPI Infrastructure Round 1
  2011-05-18 15:10     ` Luiz Capitulino
@ 2011-05-18 16:33       ` Michael Roth
  2011-05-18 17:45         ` Luiz Capitulino
  0 siblings, 1 reply; 36+ messages in thread
From: Michael Roth @ 2011-05-18 16:33 UTC (permalink / raw)
  To: Luiz Capitulino; +Cc: aliguori, qemu-devel, Markus Armbruster

On 05/18/2011 10:10 AM, Luiz Capitulino wrote:
> On Wed, 18 May 2011 09:43:37 -0500
> Michael Roth<mdroth@linux.vnet.ibm.com>  wrote:
>
>> On 05/18/2011 08:46 AM, Luiz Capitulino wrote:
>>> On Tue, 17 May 2011 19:51:47 -0500
>>> Michael Roth<mdroth@linux.vnet.ibm.com>   wrote:
>>>
>>>> These apply on top of master, and can also be obtained from:
>>>> git://repo.or.cz/qemu/mdroth.git qapi_round1_v1
>>>
>>> Nice to see this moving forward.
>>>
>>>> These patches are a backport of some of the QAPI-related work from Anthony's
>>>> glib tree. The main goal is to get the basic code generation infrastructure in
>>>> place so that it can be used by the guest agent to implement a QMP-like guest
>>>> interface, and so that future work regarding the QMP conversion to QAPI can be
>>>> decoupled from the infrastructure bits.
>>>>
>>>> Round1 incorporates the following components from Anthony's tree:
>>>>
>>>>    - Pulls in GLib libraries (core GLib, GThreads, and GIO)
>>>>
>>>>    - Adds code to do exception-like error propagation
>>>>
>>>>    - New error reporting functions
>>>>
>>>>    - Schema-based code generation for QAPI types and synchronous QMP commands
>>>>      using visiter patterns to cut reduce the amount of code generated by the
>>>>      previous scripts. This is just infrastructure, QMP will remain untouched
>>>>      until the actual conversion efforts are underway. Only a set of unit tests
>>>>      and, in the guest, virtagent, will utilize this infrastructure initially.
>>>
>>> This series introduces quite a lot of infrastructure w/o adding a single real
>>> user. This has some disadvantages, the most important one being that we can't
>>> test it for real (unit-tests are important, but don't replace real usage).
>>> Another disadvantage is that, reviewers don't actually see how this is going to
>>> be used and can't comment on API level improvements/bugs.
>>
>> The guest agent user will mirror the QMP user pretty closely, but I
>> could see why it'd be nice to have an actual QMP user as part of the
>> series. I think we decided on IRC that an incremental QMP conversion
>> wouldn't be the best route and should instead be done as part of a
>> single concerted effort. So one approach I would propose is to have
>> example conversions tacked on to the end of this series.
>
> Yes, that would be good.
>
>> So for this series we'd have 1 or 2 example conversions for synchronous
>> QMP functions. Future infrastructure patches could provide examples for
>> async QMP/proxied QMP/QMP event/qcfg/etc users as the relevant
>> infrastructure bits are added.
>
> I think the examples have to use all the added infrastructure. For example,
> if you're not adding async commands, then we'd have to drop the async support
> from the series.

Yup I agree. I actually tried to cull some of the async/proxy stuff from 
this series but there were some hooks and code gen bits I left in. I'll 
clean it up a bit better for the next submission.

>
> I'm tempted to say that we should try to reduce the code generator (and all
> the infrastructure around it) to generated only the bits that are going to be
> used by the examples. But I'm not sure if the work involved is worth it.
>

It wouldn't be too bad for this submission, far as I can tell. 
Generation of async QMP commands and event types are the main thing 
ones. The main complication is losing work from the glib tree if we're 
not careful, since the initial commits were pretty much the whole 
shebang. But it shouldn't be too difficult to piece things back together 
as we go.

>> So long as the example conversions capture the general use cases, we'd
>> still be able to decouple conversion efforts from infrastructure (with
>> any corner cases fixed as a part of those efforts), while allowing the
>> infrastructure code to be reviewed in the proper context.
>
> Yes.
>
>>> I prefer an incremental approach. We could try to split this series in smaller
>>> parts and change current QMP to use that parts. This will make review easier
>>> and will make it possible to do incremental testing too.
>>>
>>
>> I could split the code conversion stuff out into a separate series. So
>> we'd have:
>
> Looks good to me.
>
>> Round 1: error-related changes
>
> I'm already taking care of this one. I hope to have patches soon. The problem
> here is that I'm very serious about testing and am going to test each
> converted handler. Unfortunately, most of the testing is done by hand today :(
> but kvm-autotest has some support for testing error paths and libvirt has a
> more general suite too.
>

Ok, cool. A pretty good swath of the error stuff is needed to avoid 
breakage for Round 2/3, but if you can point me to a repo I can base 
this series on that and send you patches for error-related dependencies.

>> Round 2: json-related changes
>
> I think I saw patches flying on the list, did you submit then? Do they
> depend on the error stuff?
>

That was probably a pull request I sent a week or so ago to Anthony for 
the glib tree. I think they got lost in the noise of all this reworking. 
I'd also been carrying them in my virtagent series for a while. Round 2 
would have those as well as the ones in the glib tree. I'll make sure to 
give those a good bit of testing.

Some of them do make use of error propagation, but that's it as far as I 
can tell.

>> Round 3: code conversion infra + examples
>>
>> If we take the approach mentioned above, anyway.
>>
>> Otherwise I don't see how we could decouple any QMP conversion efforts
>> from infrastructure (which I think was considered desirable). In terms
>> of the code generation it's basically all or nothing, with the exception
>> of the unit tests we've added. Did you have something else in mind?
>
> Your plan looks good to me. I mean, maybe it' me who's is still catching up
> with all that stuff and want it to go slower so that I can fully absorb it
> and try to make sure it won't break anything before it's merged.
>
> On the other hand, we might want to discuss errors separately for example,
> as it's not specified to QMP.
>

Yah, hopefully the proposed Rounds are granular enough that everyone can 
absorb what's going on. Stefan H. also suggested adding some 
documentation for schema/code generation usage, which might help in that 
department as well. I'll try to get that included.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [Qemu-devel] [PATCH v1 00/23] QAPI Infrastructure Round 1
  2011-05-18 16:33       ` Michael Roth
@ 2011-05-18 17:45         ` Luiz Capitulino
  0 siblings, 0 replies; 36+ messages in thread
From: Luiz Capitulino @ 2011-05-18 17:45 UTC (permalink / raw)
  To: Michael Roth; +Cc: aliguori, qemu-devel, Markus Armbruster

On Wed, 18 May 2011 11:33:20 -0500
Michael Roth <mdroth@linux.vnet.ibm.com> wrote:

> On 05/18/2011 10:10 AM, Luiz Capitulino wrote:
> > On Wed, 18 May 2011 09:43:37 -0500
> > Michael Roth<mdroth@linux.vnet.ibm.com>  wrote:
> >
> >> On 05/18/2011 08:46 AM, Luiz Capitulino wrote:
> >>> On Tue, 17 May 2011 19:51:47 -0500
> >>> Michael Roth<mdroth@linux.vnet.ibm.com>   wrote:
> >>>
> >>>> These apply on top of master, and can also be obtained from:
> >>>> git://repo.or.cz/qemu/mdroth.git qapi_round1_v1
> >>>
> >>> Nice to see this moving forward.
> >>>
> >>>> These patches are a backport of some of the QAPI-related work from Anthony's
> >>>> glib tree. The main goal is to get the basic code generation infrastructure in
> >>>> place so that it can be used by the guest agent to implement a QMP-like guest
> >>>> interface, and so that future work regarding the QMP conversion to QAPI can be
> >>>> decoupled from the infrastructure bits.
> >>>>
> >>>> Round1 incorporates the following components from Anthony's tree:
> >>>>
> >>>>    - Pulls in GLib libraries (core GLib, GThreads, and GIO)
> >>>>
> >>>>    - Adds code to do exception-like error propagation
> >>>>
> >>>>    - New error reporting functions
> >>>>
> >>>>    - Schema-based code generation for QAPI types and synchronous QMP commands
> >>>>      using visiter patterns to cut reduce the amount of code generated by the
> >>>>      previous scripts. This is just infrastructure, QMP will remain untouched
> >>>>      until the actual conversion efforts are underway. Only a set of unit tests
> >>>>      and, in the guest, virtagent, will utilize this infrastructure initially.
> >>>
> >>> This series introduces quite a lot of infrastructure w/o adding a single real
> >>> user. This has some disadvantages, the most important one being that we can't
> >>> test it for real (unit-tests are important, but don't replace real usage).
> >>> Another disadvantage is that, reviewers don't actually see how this is going to
> >>> be used and can't comment on API level improvements/bugs.
> >>
> >> The guest agent user will mirror the QMP user pretty closely, but I
> >> could see why it'd be nice to have an actual QMP user as part of the
> >> series. I think we decided on IRC that an incremental QMP conversion
> >> wouldn't be the best route and should instead be done as part of a
> >> single concerted effort. So one approach I would propose is to have
> >> example conversions tacked on to the end of this series.
> >
> > Yes, that would be good.
> >
> >> So for this series we'd have 1 or 2 example conversions for synchronous
> >> QMP functions. Future infrastructure patches could provide examples for
> >> async QMP/proxied QMP/QMP event/qcfg/etc users as the relevant
> >> infrastructure bits are added.
> >
> > I think the examples have to use all the added infrastructure. For example,
> > if you're not adding async commands, then we'd have to drop the async support
> > from the series.
> 
> Yup I agree. I actually tried to cull some of the async/proxy stuff from 
> this series but there were some hooks and code gen bits I left in. I'll 
> clean it up a bit better for the next submission.
> 
> >
> > I'm tempted to say that we should try to reduce the code generator (and all
> > the infrastructure around it) to generated only the bits that are going to be
> > used by the examples. But I'm not sure if the work involved is worth it.
> >
> 
> It wouldn't be too bad for this submission, far as I can tell. 
> Generation of async QMP commands and event types are the main thing 
> ones. The main complication is losing work from the glib tree if we're 
> not careful, since the initial commits were pretty much the whole 
> shebang. But it shouldn't be too difficult to piece things back together 
> as we go.

Nice.

> >> So long as the example conversions capture the general use cases, we'd
> >> still be able to decouple conversion efforts from infrastructure (with
> >> any corner cases fixed as a part of those efforts), while allowing the
> >> infrastructure code to be reviewed in the proper context.
> >
> > Yes.
> >
> >>> I prefer an incremental approach. We could try to split this series in smaller
> >>> parts and change current QMP to use that parts. This will make review easier
> >>> and will make it possible to do incremental testing too.
> >>>
> >>
> >> I could split the code conversion stuff out into a separate series. So
> >> we'd have:
> >
> > Looks good to me.
> >
> >> Round 1: error-related changes
> >
> > I'm already taking care of this one. I hope to have patches soon. The problem
> > here is that I'm very serious about testing and am going to test each
> > converted handler. Unfortunately, most of the testing is done by hand today :(
> > but kvm-autotest has some support for testing error paths and libvirt has a
> > more general suite too.
> >
> 
> Ok, cool. A pretty good swath of the error stuff is needed to avoid 
> breakage for Round 2/3, but if you can point me to a repo I can base 
> this series on that and send you patches for error-related dependencies.

That's my repo:

 git://repo.or.cz/qemu/qmp-unstable.git qapi-qerror-v1

But be aware that I rebase it often.

> 
> >> Round 2: json-related changes
> >
> > I think I saw patches flying on the list, did you submit then? Do they
> > depend on the error stuff?
> >
> 
> That was probably a pull request I sent a week or so ago to Anthony for 
> the glib tree. I think they got lost in the noise of all this reworking. 
> I'd also been carrying them in my virtagent series for a while. Round 2 
> would have those as well as the ones in the glib tree. I'll make sure to 
> give those a good bit of testing.
> 
> Some of them do make use of error propagation, but that's it as far as I 
> can tell.
> 
> >> Round 3: code conversion infra + examples
> >>
> >> If we take the approach mentioned above, anyway.
> >>
> >> Otherwise I don't see how we could decouple any QMP conversion efforts
> >> from infrastructure (which I think was considered desirable). In terms
> >> of the code generation it's basically all or nothing, with the exception
> >> of the unit tests we've added. Did you have something else in mind?
> >
> > Your plan looks good to me. I mean, maybe it' me who's is still catching up
> > with all that stuff and want it to go slower so that I can fully absorb it
> > and try to make sure it won't break anything before it's merged.
> >
> > On the other hand, we might want to discuss errors separately for example,
> > as it's not specified to QMP.
> >
> 
> Yah, hopefully the proposed Rounds are granular enough that everyone can 
> absorb what's going on. Stefan H. also suggested adding some 
> documentation for schema/code generation usage, which might help in that 
> department as well. I'll try to get that included.
> 

^ permalink raw reply	[flat|nested] 36+ messages in thread

end of thread, other threads:[~2011-05-18 17:45 UTC | newest]

Thread overview: 36+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-05-18  0:51 [Qemu-devel] [PATCH v1 00/23] QAPI Infrastructure Round 1 Michael Roth
2011-05-18  0:51 ` [Qemu-devel] [PATCH v1][ 01/23] Add hard build dependency on glib Michael Roth
2011-05-18  0:51 ` [Qemu-devel] [PATCH v1][ 02/23] error-propagation: base code for error propagation Michael Roth
2011-05-18  0:51 ` [Qemu-devel] [PATCH v1][ 03/23] error-propagation: build qemu with with error-propagation bits Michael Roth
2011-05-18 13:53   ` Luiz Capitulino
2011-05-18  0:51 ` [Qemu-devel] [PATCH v1][ 04/23] qerror: refactor error to make the human message reusable Michael Roth
2011-05-18  8:09   ` Stefan Hajnoczi
2011-05-18 13:54     ` Luiz Capitulino
2011-05-18  0:51 ` [Qemu-devel] [PATCH v1][ 05/23] qlist: add qlist_first()/qlist_next() Michael Roth
2011-05-18  8:12   ` Stefan Hajnoczi
2011-05-18  0:51 ` [Qemu-devel] [PATCH v1][ 06/23] qapi: add module init types for qapi Michael Roth
2011-05-18  0:51 ` [Qemu-devel] [PATCH v1][ 07/23] qapi: add ordereddict/qapi.py helper libraries Michael Roth
2011-05-18  0:51 ` [Qemu-devel] [PATCH v1][ 08/23] qapi: add qapi-types.py code generator Michael Roth
2011-05-18  0:51 ` [Qemu-devel] [PATCH v1][ 09/23] qapi: add qapi-visit.py " Michael Roth
2011-05-18  0:51 ` [Qemu-devel] [PATCH v1][ 10/23] qapi: add qapi-commands.py " Michael Roth
2011-05-18  0:51 ` [Qemu-devel] [PATCH v1][ 11/23] qapi: add qapi-types-core.h Michael Roth
2011-05-18  0:51 ` [Qemu-devel] [PATCH v1][ 12/23] qapi: add qapi-visit-core.h Michael Roth
2011-05-18  0:52 ` [Qemu-devel] [PATCH v1][ 13/23] qapi: add QMP input visiter Michael Roth
2011-05-18  8:35   ` Stefan Hajnoczi
2011-05-18  0:52 ` [Qemu-devel] [PATCH v1][ 14/23] qapi: add QMP output visiter Michael Roth
2011-05-18  8:44   ` Stefan Hajnoczi
2011-05-18  0:52 ` [Qemu-devel] [PATCH v1][ 15/23] qapi: add QAPI dealloc visiter Michael Roth
2011-05-18  0:52 ` [Qemu-devel] [PATCH v1][ 16/23] qapi: add command registration/lookup functions Michael Roth
2011-05-18  0:52 ` [Qemu-devel] [PATCH v1][ 17/23] qapi: add QMP dispatch functions Michael Roth
2011-05-18  8:58   ` Stefan Hajnoczi
2011-05-18  0:52 ` [Qemu-devel] [PATCH v1][ 18/23] qapi: add base declaration/types for QMP Michael Roth
2011-05-18  0:52 ` [Qemu-devel] [PATCH v1][ 19/23] qapi: test schema used for unit tests Michael Roth
2011-05-18  0:52 ` [Qemu-devel] [PATCH v1][ 20/23] qapi: add test-visiter, tests for gen. visiter code Michael Roth
2011-05-18  0:52 ` [Qemu-devel] [PATCH v1][ 21/23] qapi: Makefile changes to build test-visiter Michael Roth
2011-05-18  0:52 ` [Qemu-devel] [PATCH v1][ 22/23] qapi: add test-qmp-commands, tests for gen. marshalling/dispatch code Michael Roth
2011-05-18  0:52 ` [Qemu-devel] [PATCH v1][ 23/23] qapi: Makefile changes to build test-qmp-commands Michael Roth
2011-05-18 13:46 ` [Qemu-devel] [PATCH v1 00/23] QAPI Infrastructure Round 1 Luiz Capitulino
2011-05-18 14:43   ` Michael Roth
2011-05-18 15:10     ` Luiz Capitulino
2011-05-18 16:33       ` Michael Roth
2011-05-18 17:45         ` Luiz Capitulino

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.