All of lore.kernel.org
 help / color / mirror / Atom feed
From: Eric Blake <eblake@redhat.com>
To: qemu-devel@nongnu.org
Cc: "Michael S. Tsirkin" <mst@redhat.com>,
	armbru@redhat.com, "Michael Roth" <mdroth@linux.vnet.ibm.com>,
	"Alexander Graf" <agraf@suse.de>,
	"open list:sPAPR pseries" <qemu-ppc@nongnu.org>,
	"Paolo Bonzini" <pbonzini@redhat.com>,
	"Luiz Capitulino" <lcapitulino@redhat.com>,
	"Andreas Färber" <afaerber@suse.de>,
	"David Gibson" <david@gibson.dropbear.id.au>
Subject: [Qemu-devel] [PATCH v7 28/31] qapi: Split visit_end_struct() into pieces
Date: Mon,  7 Dec 2015 20:55:18 -0700	[thread overview]
Message-ID: <1449546921-6378-29-git-send-email-eblake@redhat.com> (raw)
In-Reply-To: <1449546921-6378-1-git-send-email-eblake@redhat.com>

As mentioned in previous patches, we want to call visit_end_struct()
functions unconditionally, so that visitors can release resources
tied up since the matching visit_start_struct() without also having
to worry about error priority if more than one error occurs.

Even though error_propagate() can be safely used to ignore a second
error during cleanup caused by a first error, it is simpler if the
cleanup cannot set an error, and we instead split the task of
checking that an input visitor has no unvisited input as a new
function visit_check_struct(), called only if all prior steps are
successful.

Generated code has diffs resembling:

|@@ -59,10 +59,12 @@ void visit_type_ACPIOSTInfo(Visitor *v,
|         goto out_obj;
|     }
|     visit_type_ACPIOSTInfo_fields(v, obj, &err);
|+    if (err) {
|+        goto out_obj;
|+    }
|+    visit_check_struct(v, &err);
| out_obj:
|-    error_propagate(errp, err);
|-    err = NULL;
|-    visit_end_struct(v, &err);
|+    visit_end_struct(v);
| out:

Signed-off-by: Eric Blake <eblake@redhat.com>

---
v7: rebase to earlier changes
v6: new patch, revised version of RFC based on discussion of v5 7/46
---
 hmp.c                       |  7 ++++---
 hw/ppc/spapr_drc.c          |  3 ++-
 hw/virtio/virtio-balloon.c  | 12 ++++++------
 include/qapi/visitor-impl.h |  4 +++-
 include/qapi/visitor.h      | 13 ++++++++++---
 qapi/opts-visitor.c         | 17 +++++++++++++++--
 qapi/qapi-dealloc-visitor.c |  2 +-
 qapi/qapi-visit-core.c      | 11 +++++++++--
 qapi/qmp-input-visitor.c    | 34 +++++++++++++++++++---------------
 qapi/qmp-output-visitor.c   |  2 +-
 qom/object.c                |  5 ++---
 scripts/qapi-event.py       |  3 ++-
 scripts/qapi-visit.py       |  9 ++++-----
 vl.c                        | 11 +++++------
 14 files changed, 83 insertions(+), 50 deletions(-)

diff --git a/hmp.c b/hmp.c
index f81f332..35cd625 100644
--- a/hmp.c
+++ b/hmp.c
@@ -1698,13 +1698,14 @@ void hmp_object_add(Monitor *mon, const QDict *qdict)
     }

     object_add(type, id, pdict, v, &err);
-
-out_end:
-    visit_end_struct(v, &err_end);
+    visit_check_struct(v, &err_end);
     if (!err && err_end) {
         qmp_object_del(id, NULL);
     }
     error_propagate(&err, err_end);
+
+out_end:
+    visit_end_struct(v);
 out_clean:
     opts_visitor_cleanup(ov);

diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c
index 0c675ff..65764bc 100644
--- a/hw/ppc/spapr_drc.c
+++ b/hw/ppc/spapr_drc.c
@@ -287,11 +287,12 @@ static void prop_get_fdt(Object *obj, Visitor *v, void *opaque,
         case FDT_END_NODE:
             /* shouldn't ever see an FDT_END_NODE before FDT_BEGIN_NODE */
             g_assert(fdt_depth > 0);
-            visit_end_struct(v, &err);
+            visit_check_struct(v, &err);
             if (err) {
                 error_propagate(errp, err);
                 return;
             }
+            visit_end_struct(v);
             fdt_depth--;
             break;
         case FDT_PROP: {
diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c
index cb8237f..fc3bced 100644
--- a/hw/virtio/virtio-balloon.c
+++ b/hw/virtio/virtio-balloon.c
@@ -136,15 +136,15 @@ static void balloon_stats_get_all(Object *obj, struct Visitor *v,
             goto out_nested;
         }
     }
+    visit_check_struct(v, &err);
 out_nested:
-    error_propagate(errp, err);
-    err = NULL;
-    visit_end_struct(v, &err);
+    visit_end_struct(v);

+    if (!err) {
+        visit_check_struct(v, &err);
+    }
 out_end:
-    error_propagate(errp, err);
-    err = NULL;
-    visit_end_struct(v, &err);
+    visit_end_struct(v);
 out:
     error_propagate(errp, err);
 }
diff --git a/include/qapi/visitor-impl.h b/include/qapi/visitor-impl.h
index 3b67dc7..d1f4f78 100644
--- a/include/qapi/visitor-impl.h
+++ b/include/qapi/visitor-impl.h
@@ -28,8 +28,10 @@ struct Visitor
      * currently visit structs). */
     void (*start_struct)(Visitor *v, void **obj, size_t size,
                          const char *name, Error **errp);
+    /* May be NULL; most useful for input visitors. */
+    void (*check_struct)(Visitor *v, Error **errp);
     /* Must be provided if start_struct is present. */
-    void (*end_struct)(Visitor *v, Error **errp);
+    void (*end_struct)(Visitor *v);

     /* May be NULL; most useful for input visitors. */
     void (*start_implicit_struct)(Visitor *v, void **obj, size_t size,
diff --git a/include/qapi/visitor.h b/include/qapi/visitor.h
index b8146d7..f83707a 100644
--- a/include/qapi/visitor.h
+++ b/include/qapi/visitor.h
@@ -68,12 +68,19 @@ typedef struct GenericList
 void visit_start_struct(Visitor *v, void **obj, size_t size,
                         const char *name, Error **errp);
 /**
+ * Prepare for completing a struct visit.
+ * Should be called prior to visit_end_struct() if all other intermediate
+ * visit steps were successful, to allow the caller one last chance to
+ * report errors such as remaining data that was not consumed by the visit.
+ */
+void visit_check_struct(Visitor *v, Error **errp);
+/**
  * Complete a struct visit started earlier.
  * Must be called after any successful use of visit_start_struct(),
  * even if intermediate processing was skipped due to errors, to allow
  * the backend to release any resources.
  */
-void visit_end_struct(Visitor *v, Error **errp);
+void visit_end_struct(Visitor *v);

 /**
  * Prepare to visit an implicit struct.
@@ -96,8 +103,8 @@ void visit_start_implicit_struct(Visitor *v, void **obj, size_t size,
  * Must be called after any successful use of visit_start_implicit_struct(),
  * even if intermediate processing was skipped due to errors, to allow
  * the backend to release any resources.  Unlike visit_end_struct(), this
- * does not need to check for errors (detection of unused keys is only
- * possible for the overall struct, not a subset).
+ * does not need a counterpart function to check for errors (detection of
+ * unused keys is only possible for the overall struct, not a subset).
  */
 void visit_end_implicit_struct(Visitor *v);

diff --git a/qapi/opts-visitor.c b/qapi/opts-visitor.c
index a767391..fabf3d7 100644
--- a/qapi/opts-visitor.c
+++ b/qapi/opts-visitor.c
@@ -157,13 +157,13 @@ opts_start_struct(Visitor *v, void **obj, size_t size,


 static void
-opts_end_struct(Visitor *v, Error **errp)
+opts_check_struct(Visitor *v, Error **errp)
 {
     OptsVisitor *ov = to_ov(v);
     GHashTableIter iter;
     GQueue *any;

-    if (--ov->depth > 0) {
+    if (ov->depth > 0) {
         return;
     }

@@ -175,6 +175,18 @@ opts_end_struct(Visitor *v, Error **errp)
         first = g_queue_peek_head(any);
         error_setg(errp, QERR_INVALID_PARAMETER, first->name);
     }
+}
+
+
+static void
+opts_end_struct(Visitor *v)
+{
+    OptsVisitor *ov = DO_UPCAST(OptsVisitor, visitor, v);
+
+    if (--ov->depth > 0) {
+        return;
+    }
+
     g_hash_table_destroy(ov->unprocessed_opts);
     ov->unprocessed_opts = NULL;
     if (ov->fake_id_opt) {
@@ -506,6 +518,7 @@ opts_visitor_new(const QemuOpts *opts)
     ov = g_malloc0(sizeof *ov);

     ov->visitor.start_struct = &opts_start_struct;
+    ov->visitor.check_struct = &opts_check_struct;
     ov->visitor.end_struct   = &opts_end_struct;

     ov->visitor.start_list = &opts_start_list;
diff --git a/qapi/qapi-dealloc-visitor.c b/qapi/qapi-dealloc-visitor.c
index 92345aa..d3f9171 100644
--- a/qapi/qapi-dealloc-visitor.c
+++ b/qapi/qapi-dealloc-visitor.c
@@ -65,7 +65,7 @@ static void qapi_dealloc_start_struct(Visitor *v, void **obj, size_t unused,
     qapi_dealloc_push(qov, obj);
 }

-static void qapi_dealloc_end_struct(Visitor *v, Error **errp)
+static void qapi_dealloc_end_struct(Visitor *v)
 {
     QapiDeallocVisitor *qov = to_qov(v);
     void **obj = qapi_dealloc_pop(qov);
diff --git a/qapi/qapi-visit-core.c b/qapi/qapi-visit-core.c
index 09cc5c9..a3b59f7 100644
--- a/qapi/qapi-visit-core.c
+++ b/qapi/qapi-visit-core.c
@@ -36,9 +36,16 @@ void visit_start_struct(Visitor *v, void **obj, size_t size,
     v->start_struct(v, obj, size, name, errp);
 }

-void visit_end_struct(Visitor *v, Error **errp)
+void visit_check_struct(Visitor *v, Error **errp)
 {
-    v->end_struct(v, errp);
+    if (v->check_struct) {
+        v->check_struct(v, errp);
+    }
+}
+
+void visit_end_struct(Visitor *v)
+{
+    v->end_struct(v);
 }

 void visit_start_implicit_struct(Visitor *v, void **obj, size_t size,
diff --git a/qapi/qmp-input-visitor.c b/qapi/qmp-input-visitor.c
index 0587b8e..18c963b 100644
--- a/qapi/qmp-input-visitor.c
+++ b/qapi/qmp-input-visitor.c
@@ -89,8 +89,10 @@ static void qmp_input_push(QmpInputVisitor *qiv, QObject *obj, Error **errp)
 }


-static void qmp_input_pop(QmpInputVisitor *qiv, Error **errp)
+static void qmp_input_check_struct(Visitor *v, Error **errp)
 {
+    QmpInputVisitor *qiv = to_qiv(v);
+
     assert(qiv->nb_stack > 0);

     if (qiv->strict) {
@@ -103,6 +105,19 @@ static void qmp_input_pop(QmpInputVisitor *qiv, Error **errp)
             if (g_hash_table_iter_next(&iter, (void **)&key, NULL)) {
                 error_setg(errp, QERR_QMP_EXTRA_MEMBER, key);
             }
+        }
+    }
+}
+
+static void qmp_input_pop(Visitor *v)
+{
+    QmpInputVisitor *qiv = to_qiv(v);
+
+    assert(qiv->nb_stack > 0);
+
+    if (qiv->strict) {
+        GHashTable * const top_ht = qiv->stack[qiv->nb_stack - 1].h;
+        if (top_ht) {
             g_hash_table_unref(top_ht);
         }
     }
@@ -134,12 +149,6 @@ static void qmp_input_start_struct(Visitor *v, void **obj, size_t size,
     }
 }

-static void qmp_input_end_struct(Visitor *v, Error **errp)
-{
-    QmpInputVisitor *qiv = to_qiv(v);
-
-    qmp_input_pop(qiv, errp);
-}

 static void qmp_input_start_implicit_struct(Visitor *v, void **obj,
                                             size_t size, Error **errp)
@@ -193,12 +202,6 @@ static GenericList *qmp_input_next_list(Visitor *v, GenericList **list,
     return entry;
 }

-static void qmp_input_end_list(Visitor *v)
-{
-    QmpInputVisitor *qiv = to_qiv(v);
-
-    qmp_input_pop(qiv, &error_abort);
-}

 static void qmp_input_get_next_type(Visitor *v, QType *type, bool promote_int,
                                     const char *name, Error **errp)
@@ -342,11 +345,12 @@ QmpInputVisitor *qmp_input_visitor_new(QObject *obj)
     v = g_malloc0(sizeof(*v));

     v->visitor.start_struct = qmp_input_start_struct;
-    v->visitor.end_struct = qmp_input_end_struct;
+    v->visitor.check_struct = qmp_input_check_struct;
+    v->visitor.end_struct = qmp_input_pop;
     v->visitor.start_implicit_struct = qmp_input_start_implicit_struct;
     v->visitor.start_list = qmp_input_start_list;
     v->visitor.next_list = qmp_input_next_list;
-    v->visitor.end_list = qmp_input_end_list;
+    v->visitor.end_list = qmp_input_pop;
     v->visitor.type_enum = input_type_enum;
     v->visitor.type_int64 = qmp_input_type_int64;
     v->visitor.type_uint64 = qmp_input_type_uint64;
diff --git a/qapi/qmp-output-visitor.c b/qapi/qmp-output-visitor.c
index 28f9854..1ffe820 100644
--- a/qapi/qmp-output-visitor.c
+++ b/qapi/qmp-output-visitor.c
@@ -117,7 +117,7 @@ static void qmp_output_start_struct(Visitor *v, void **obj, size_t unused,
     qmp_output_push(qov, dict);
 }

-static void qmp_output_end_struct(Visitor *v, Error **errp)
+static void qmp_output_end_struct(Visitor *v)
 {
     QmpOutputVisitor *qov = to_qov(v);
     qmp_output_pop(qov);
diff --git a/qom/object.c b/qom/object.c
index 5eb65ea..36de3a2 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -1904,10 +1904,9 @@ static void property_get_tm(Object *obj, Visitor *v, void *opaque,
     if (err) {
         goto out_end;
     }
+    visit_check_struct(v, &err);
 out_end:
-    error_propagate(errp, err);
-    err = NULL;
-    visit_end_struct(v, errp);
+    visit_end_struct(v);
 out:
     error_propagate(errp, err);

diff --git a/scripts/qapi-event.py b/scripts/qapi-event.py
index 6a29b6c..83f1257 100644
--- a/scripts/qapi-event.py
+++ b/scripts/qapi-event.py
@@ -71,8 +71,9 @@ def gen_event_send(name, arg_type):
         ret += gen_visit_fields(arg_type.members, need_cast=True,
                                 label='out_obj')
         ret += mcgen('''
+    visit_check_struct(v, &err);
 out_obj:
-    visit_end_struct(v, &err);
+    visit_end_struct(v);
     if (err) {
         goto out;
     }
diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
index 5c8f1e6..694951f 100644
--- a/scripts/qapi-visit.py
+++ b/scripts/qapi-visit.py
@@ -255,8 +255,7 @@ void visit_type_%(c_name)s(Visitor *v, %(c_name)s **obj, const char *name, Error
     visit_type_%(c_name)s_fields(v, %(cast)sobj, &err);
 ''',
                      c_name=type_name, cast=cast)
-        if variants:
-            ret += gen_err_check(label='out_obj')
+        ret += gen_err_check(label='out_obj')

     if variants:
         ret += mcgen('''
@@ -293,12 +292,12 @@ void visit_type_%(c_name)s(Visitor *v, %(c_name)s **obj, const char *name, Error
         abort();
     }
 ''')
+        ret += gen_err_check(label='out_obj')

     ret += mcgen('''
+    visit_check_struct(v, &err);
 out_obj:
-    error_propagate(errp, err);
-    err = NULL;
-    visit_end_struct(v, &err);
+    visit_end_struct(v);
 out:
     error_propagate(errp, err);
 }
diff --git a/vl.c b/vl.c
index 1010bdb..ed1203e 100644
--- a/vl.c
+++ b/vl.c
@@ -2848,11 +2848,10 @@ static int object_create(void *opaque, QemuOpts *opts, Error **errp)
     qdict_del(pdict, "qom-type");
     visit_type_str(v, &type, "qom-type", &err);
     if (err) {
-        goto out;
+        goto out_end;
     }
     if (!type_predicate(type)) {
-        visit_end_struct(v, NULL);
-        goto out;
+        goto out_end;
     }

     qdict_del(pdict, "id");
@@ -2862,14 +2861,14 @@ static int object_create(void *opaque, QemuOpts *opts, Error **errp)
     }

     object_add(type, id, pdict, v, &err);
-
-out_end:
-    visit_end_struct(v, &err_end);
+    visit_check_struct(v, &err_end);
     if (!err && err_end) {
         qmp_object_del(id, NULL);
     }
     error_propagate(&err, err_end);

+out_end:
+    visit_end_struct(v);
 out:
     opts_visitor_cleanup(ov);

-- 
2.4.3

  parent reply	other threads:[~2015-12-08  3:55 UTC|newest]

Thread overview: 41+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-12-08  3:54 [Qemu-devel] [PATCH v7 00/31] qapi visitor cleanups (post-introspection cleanups subset E) Eric Blake
2015-12-08  3:54 ` [Qemu-devel] [PATCH v7 01/31] qobject: Document more shortcomings in our number handling Eric Blake
2015-12-08  3:54 ` [Qemu-devel] [PATCH v7 02/31] qapi: Avoid use of misnamed DO_UPCAST() Eric Blake
2015-12-08  3:54 ` [Qemu-devel] [PATCH v7 03/31] qapi: Drop dead dealloc visitor variable Eric Blake
2015-12-08  3:54 ` [Qemu-devel] [PATCH v7 04/31] hmp: Improve use of qapi visitor Eric Blake
2015-12-08  3:54 ` [Qemu-devel] [PATCH v7 05/31] vl: " Eric Blake
2015-12-08  3:54 ` [Qemu-devel] [PATCH v7 06/31] balloon: " Eric Blake
2015-12-08  3:54 ` [Qemu-devel] [PATCH v7 07/31] qapi: Improve generated event " Eric Blake
2015-12-08  3:54 ` [Qemu-devel] [PATCH v7 08/31] qapi: Track all failures between visit_start/stop Eric Blake
2015-12-08  3:54 ` [Qemu-devel] [PATCH v7 09/31] qapi: Prefer type_int64 over type_int in visitors Eric Blake
2015-12-08  3:55 ` [Qemu-devel] [PATCH v7 10/31] qapi: Make all visitors supply uint64 callbacks Eric Blake
2015-12-08  3:55 ` [Qemu-devel] [PATCH v7 11/31] qapi: Consolidate visitor small integer callbacks Eric Blake
2015-12-08  3:55 ` [Qemu-devel] [PATCH v7 12/31] qapi: Don't cast Enum* to int* Eric Blake
2015-12-08  3:55 ` [Qemu-devel] [PATCH v7 13/31] qapi: Drop unused 'kind' for struct/enum visit Eric Blake
2015-12-08  4:40   ` David Gibson
2015-12-11 13:51   ` Eric Blake
2015-12-08  3:55 ` [Qemu-devel] [PATCH v7 14/31] qapi: Drop unused error argument for list and implicit struct Eric Blake
2015-12-08  4:40   ` David Gibson
2015-12-08  3:55 ` [Qemu-devel] [PATCH v7 15/31] qmp: Fix reference-counting of qnull on empty output visit Eric Blake
2015-12-08  3:55 ` [Qemu-devel] [PATCH v7 16/31] qmp: Don't abuse stack to track qmp-output root Eric Blake
2015-12-08  3:55 ` [Qemu-devel] [PATCH v7 17/31] qapi: Document visitor interfaces, add assertions Eric Blake
2015-12-08  3:55 ` [Qemu-devel] [PATCH v7 18/31] qapi: Add visit_type_null() visitor Eric Blake
2015-12-08  3:55 ` [Qemu-devel] [PATCH v7 19/31] qmp: Tighten output visitor rules Eric Blake
2015-12-08  3:55 ` [Qemu-devel] [PATCH v7 20/31] spapr_drc: Expose 'null' in qom-get when there is no fdt Eric Blake
2015-12-08  4:40   ` David Gibson
2015-12-08  3:55 ` [Qemu-devel] [PATCH v7 21/31] qapi: Simplify excess input reporting in input visitors Eric Blake
2015-12-08  3:55 ` [Qemu-devel] [PATCH v7 22/31] qapi: Add type.is_empty() helper Eric Blake
2015-12-08  3:55 ` [Qemu-devel] [PATCH v7 23/31] qapi: Fix command with named empty argument type Eric Blake
2015-12-08  3:55 ` [Qemu-devel] [PATCH v7 24/31] qapi: Eliminate empty visit_type_FOO_fields Eric Blake
2015-12-08  3:55 ` [Qemu-devel] [PATCH v7 25/31] qapi: Canonicalize missing object to :empty Eric Blake
2015-12-08  3:55 ` [Qemu-devel] [PATCH v7 26/31] qapi-visit: Unify struct and union visit Eric Blake
2015-12-08  3:55 ` [Qemu-devel] [PATCH v7 27/31] qapi: Rework deallocation of partial struct Eric Blake
2015-12-08  3:55 ` Eric Blake [this message]
2015-12-08  4:42   ` [Qemu-devel] [PATCH v7 28/31] qapi: Split visit_end_struct() into pieces David Gibson
2015-12-08  3:55 ` [Qemu-devel] [PATCH v7 29/31] qapi: Simplify semantics of visit_next_list() Eric Blake
2015-12-08  4:51   ` David Gibson
2015-12-10 17:32   ` Eric Blake
2015-12-11  4:04     ` Eric Blake
2015-12-08  3:55 ` [Qemu-devel] [PATCH v7 30/31] qapi: Change visit_type_FOO() to no longer return partial objects Eric Blake
2015-12-08  3:55 ` [Qemu-devel] [PATCH v7 31/31] RFC: qapi: Adjust layout of FooList types Eric Blake
2015-12-08  4:54   ` David Gibson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1449546921-6378-29-git-send-email-eblake@redhat.com \
    --to=eblake@redhat.com \
    --cc=afaerber@suse.de \
    --cc=agraf@suse.de \
    --cc=armbru@redhat.com \
    --cc=david@gibson.dropbear.id.au \
    --cc=lcapitulino@redhat.com \
    --cc=mdroth@linux.vnet.ibm.com \
    --cc=mst@redhat.com \
    --cc=pbonzini@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=qemu-ppc@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.