Merge remote-tracking branch 'remotes/armbru/tags/pull-qapi-2016-07-06' into staging

QAPI patches for 2016-07-06

# gpg: Signature made Wed 06 Jul 2016 10:00:51 BST
# gpg:                using RSA key 0x3870B400EB918653
# gpg: Good signature from "Markus Armbruster <armbru@redhat.com>"
# gpg:                 aka "Markus Armbruster <armbru@pond.sub.org>"
# Primary key fingerprint: 354B C8B3 D7EB 2A6B 6867  4E5F 3870 B400 EB91 8653

* remotes/armbru/tags/pull-qapi-2016-07-06:
  replay: Use new QAPI cloning
  sockets: Use new QAPI cloning
  qapi: Add new clone visitor
  qapi: Add new visit_complete() function
  tests: Factor out common code in qapi output tests
  tests: Clean up test-string-output-visitor
  qmp-output-visitor: Favor new visit_free() function
  string-output-visitor: Favor new visit_free() function
  qmp-input-visitor: Favor new visit_free() function
  string-input-visitor: Favor new visit_free() function
  opts-visitor: Favor new visit_free() function
  qapi: Add new visit_free() function
  qapi: Add parameter to visit_end_*
  qemu-img: Don't leak errors when outputting JSON
  qapi: Improve use of qmp/types.h

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell
2016-07-06 11:38:09 +01:00
63 changed files with 1027 additions and 715 deletions
+14 -16
View File
@@ -193,17 +193,16 @@ block_crypto_open_opts_init(QCryptoBlockFormat format,
QemuOpts *opts,
Error **errp)
{
OptsVisitor *ov;
Visitor *v;
QCryptoBlockOpenOptions *ret = NULL;
Error *local_err = NULL;
ret = g_new0(QCryptoBlockOpenOptions, 1);
ret->format = format;
ov = opts_visitor_new(opts);
v = opts_visitor_new(opts);
visit_start_struct(opts_get_visitor(ov),
NULL, NULL, 0, &local_err);
visit_start_struct(v, NULL, NULL, 0, &local_err);
if (local_err) {
goto out;
}
@@ -211,7 +210,7 @@ block_crypto_open_opts_init(QCryptoBlockFormat format,
switch (format) {
case Q_CRYPTO_BLOCK_FORMAT_LUKS:
visit_type_QCryptoBlockOptionsLUKS_members(
opts_get_visitor(ov), &ret->u.luks, &local_err);
v, &ret->u.luks, &local_err);
break;
default:
@@ -219,10 +218,10 @@ block_crypto_open_opts_init(QCryptoBlockFormat format,
break;
}
if (!local_err) {
visit_check_struct(opts_get_visitor(ov), &local_err);
visit_check_struct(v, &local_err);
}
visit_end_struct(opts_get_visitor(ov));
visit_end_struct(v, NULL);
out:
if (local_err) {
@@ -230,7 +229,7 @@ block_crypto_open_opts_init(QCryptoBlockFormat format,
qapi_free_QCryptoBlockOpenOptions(ret);
ret = NULL;
}
opts_visitor_cleanup(ov);
visit_free(v);
return ret;
}
@@ -240,17 +239,16 @@ block_crypto_create_opts_init(QCryptoBlockFormat format,
QemuOpts *opts,
Error **errp)
{
OptsVisitor *ov;
Visitor *v;
QCryptoBlockCreateOptions *ret = NULL;
Error *local_err = NULL;
ret = g_new0(QCryptoBlockCreateOptions, 1);
ret->format = format;
ov = opts_visitor_new(opts);
v = opts_visitor_new(opts);
visit_start_struct(opts_get_visitor(ov),
NULL, NULL, 0, &local_err);
visit_start_struct(v, NULL, NULL, 0, &local_err);
if (local_err) {
goto out;
}
@@ -258,7 +256,7 @@ block_crypto_create_opts_init(QCryptoBlockFormat format,
switch (format) {
case Q_CRYPTO_BLOCK_FORMAT_LUKS:
visit_type_QCryptoBlockCreateOptionsLUKS_members(
opts_get_visitor(ov), &ret->u.luks, &local_err);
v, &ret->u.luks, &local_err);
break;
default:
@@ -266,10 +264,10 @@ block_crypto_create_opts_init(QCryptoBlockFormat format,
break;
}
if (!local_err) {
visit_check_struct(opts_get_visitor(ov), &local_err);
visit_check_struct(v, &local_err);
}
visit_end_struct(opts_get_visitor(ov));
visit_end_struct(v, NULL);
out:
if (local_err) {
@@ -277,7 +275,7 @@ block_crypto_create_opts_init(QCryptoBlockFormat format,
qapi_free_QCryptoBlockCreateOptions(ret);
ret = NULL;
}
opts_visitor_cleanup(ov);
visit_free(v);
return ret;
}
+4 -5
View File
@@ -690,16 +690,15 @@ static void dump_qdict(fprintf_function func_fprintf, void *f, int indentation,
void bdrv_image_info_specific_dump(fprintf_function func_fprintf, void *f,
ImageInfoSpecific *info_spec)
{
QmpOutputVisitor *ov = qmp_output_visitor_new();
QObject *obj, *data;
Visitor *v = qmp_output_visitor_new(&obj);
visit_type_ImageInfoSpecific(qmp_output_get_visitor(ov), NULL, &info_spec,
&error_abort);
obj = qmp_output_get_qobject(ov);
visit_type_ImageInfoSpecific(v, NULL, &info_spec, &error_abort);
visit_complete(v, &obj);
assert(qobject_type(obj) == QTYPE_QDICT);
data = qdict_get(qobject_to_qdict(obj), "data");
dump_qobject(func_fprintf, f, 1, data);
qmp_output_visitor_cleanup(ov);
visit_free(v);
}
void bdrv_image_info_dump(fprintf_function func_fprintf, void *f,
+4 -5
View File
@@ -3950,10 +3950,10 @@ out:
void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
{
QmpOutputVisitor *ov = qmp_output_visitor_new();
BlockDriverState *bs;
BlockBackend *blk = NULL;
QObject *obj;
Visitor *v = qmp_output_visitor_new(&obj);
QDict *qdict;
Error *local_err = NULL;
@@ -3972,14 +3972,13 @@ void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
}
}
visit_type_BlockdevOptions(qmp_output_get_visitor(ov), NULL, &options,
&local_err);
visit_type_BlockdevOptions(v, NULL, &options, &local_err);
if (local_err) {
error_propagate(errp, local_err);
goto fail;
}
obj = qmp_output_get_qobject(ov);
visit_complete(v, &obj);
qdict = qobject_to_qdict(obj);
qdict_flatten(qdict);
@@ -4020,7 +4019,7 @@ void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
}
fail:
qmp_output_visitor_cleanup(ov);
visit_free(v);
}
void qmp_x_blockdev_del(bool has_id, const char *id,
+18 -31
View File
@@ -802,32 +802,28 @@ Example:
void qapi_free_UserDefOne(UserDefOne *obj)
{
QapiDeallocVisitor *qdv;
Visitor *v;
if (!obj) {
return;
}
qdv = qapi_dealloc_visitor_new();
v = qapi_dealloc_get_visitor(qdv);
v = qapi_dealloc_visitor_new();
visit_type_UserDefOne(v, NULL, &obj, NULL);
qapi_dealloc_visitor_cleanup(qdv);
visit_free(v);
}
void qapi_free_UserDefOneList(UserDefOneList *obj)
{
QapiDeallocVisitor *qdv;
Visitor *v;
if (!obj) {
return;
}
qdv = qapi_dealloc_visitor_new();
v = qapi_dealloc_get_visitor(qdv);
v = qapi_dealloc_visitor_new();
visit_type_UserDefOneList(v, NULL, &obj, NULL);
qapi_dealloc_visitor_cleanup(qdv);
visit_free(v);
}
=== scripts/qapi-visit.py ===
@@ -904,7 +900,7 @@ Example:
}
visit_check_struct(v, &err);
out_obj:
visit_end_struct(v);
visit_end_struct(v, (void **)obj);
if (err && visit_is_input(v)) {
qapi_free_UserDefOne(*obj);
*obj = NULL;
@@ -932,7 +928,7 @@ Example:
}
}
visit_end_list(v);
visit_end_list(v, (void **)obj);
if (err && visit_is_input(v)) {
qapi_free_UserDefOneList(*obj);
*obj = NULL;
@@ -984,36 +980,28 @@ Example:
static void qmp_marshal_output_UserDefOne(UserDefOne *ret_in, QObject **ret_out, Error **errp)
{
Error *err = NULL;
QmpOutputVisitor *qov = qmp_output_visitor_new();
QapiDeallocVisitor *qdv;
Visitor *v;
v = qmp_output_get_visitor(qov);
v = qmp_output_visitor_new(ret_out);
visit_type_UserDefOne(v, "unused", &ret_in, &err);
if (err) {
goto out;
if (!err) {
visit_complete(v, ret_out);
}
*ret_out = qmp_output_get_qobject(qov);
out:
error_propagate(errp, err);
qmp_output_visitor_cleanup(qov);
qdv = qapi_dealloc_visitor_new();
v = qapi_dealloc_get_visitor(qdv);
visit_free(v);
v = qapi_dealloc_visitor_new();
visit_type_UserDefOne(v, "unused", &ret_in, NULL);
qapi_dealloc_visitor_cleanup(qdv);
visit_free(v);
}
static void qmp_marshal_my_command(QDict *args, QObject **ret, Error **errp)
{
Error *err = NULL;
UserDefOne *retval;
QmpInputVisitor *qiv = qmp_input_visitor_new(QOBJECT(args), true);
QapiDeallocVisitor *qdv;
Visitor *v;
UserDefOneList *arg1 = NULL;
v = qmp_input_get_visitor(qiv);
v = qmp_input_visitor_new(QOBJECT(args), true);
visit_start_struct(v, NULL, NULL, 0, &err);
if (err) {
goto out;
@@ -1022,7 +1010,7 @@ Example:
if (!err) {
visit_check_struct(v, &err);
}
visit_end_struct(v);
visit_end_struct(v, NULL);
if (err) {
goto out;
}
@@ -1036,13 +1024,12 @@ Example:
out:
error_propagate(errp, err);
qmp_input_visitor_cleanup(qiv);
qdv = qapi_dealloc_visitor_new();
v = qapi_dealloc_get_visitor(qdv);
visit_free(v);
v = qapi_dealloc_visitor_new();
visit_start_struct(v, NULL, NULL, 0, NULL);
visit_type_UserDefOneList(v, "arg1", &arg1, NULL);
visit_end_struct(v);
qapi_dealloc_visitor_cleanup(qdv);
visit_end_struct(v, NULL);
visit_free(v);
}
static void qmp_init_marshal(void)
+9 -10
View File
@@ -1722,7 +1722,7 @@ void hmp_object_add(Monitor *mon, const QDict *qdict)
{
Error *err = NULL;
QemuOpts *opts;
OptsVisitor *ov;
Visitor *v;
Object *obj = NULL;
opts = qemu_opts_from_qdict(qemu_find_opts("object"), qdict, &err);
@@ -1731,9 +1731,9 @@ void hmp_object_add(Monitor *mon, const QDict *qdict)
return;
}
ov = opts_visitor_new(opts);
obj = user_creatable_add(qdict, opts_get_visitor(ov), &err);
opts_visitor_cleanup(ov);
v = opts_visitor_new(opts);
obj = user_creatable_add(qdict, v, &err);
visit_free(v);
qemu_opts_del(opts);
if (err) {
@@ -1983,15 +1983,14 @@ void hmp_info_memdev(Monitor *mon, const QDict *qdict)
Error *err = NULL;
MemdevList *memdev_list = qmp_query_memdev(&err);
MemdevList *m = memdev_list;
StringOutputVisitor *ov;
Visitor *v;
char *str;
int i = 0;
while (m) {
ov = string_output_visitor_new(false);
visit_type_uint16List(string_output_get_visitor(ov), NULL,
&m->value->host_nodes, NULL);
v = string_output_visitor_new(false, &str);
visit_type_uint16List(v, NULL, &m->value->host_nodes, NULL);
monitor_printf(mon, "memory backend: %d\n", i);
monitor_printf(mon, " size: %" PRId64 "\n", m->value->size);
monitor_printf(mon, " merge: %s\n",
@@ -2002,11 +2001,11 @@ void hmp_info_memdev(Monitor *mon, const QDict *qdict)
m->value->prealloc ? "true" : "false");
monitor_printf(mon, " policy: %s\n",
HostMemPolicy_lookup[m->value->policy]);
str = string_output_get_string(ov);
visit_complete(v, &str);
monitor_printf(mon, " host nodes: %s\n", str);
g_free(str);
string_output_visitor_cleanup(ov);
visit_free(v);
m = m->next;
i++;
}
+4 -4
View File
@@ -239,11 +239,11 @@ void acpi_table_add(const QemuOpts *opts, Error **errp)
char unsigned *blob = NULL;
{
OptsVisitor *ov;
Visitor *v;
ov = opts_visitor_new(opts);
visit_type_AcpiTableOptions(opts_get_visitor(ov), NULL, &hdrs, &err);
opts_visitor_cleanup(ov);
v = opts_visitor_new(opts);
visit_type_AcpiTableOptions(v, NULL, &hdrs, &err);
visit_free(v);
}
if (err) {
+1
View File
@@ -21,6 +21,7 @@
#include "qemu/osdep.h"
#include "sysemu/sysemu.h"
#include "qapi/qmp/types.h"
#include "qapi/qmp/qjson.h"
#include "monitor/monitor.h"
#include "hw/pci/pci_bridge.h"
#include "hw/pci/pcie.h"
+2 -2
View File
@@ -300,7 +300,7 @@ static void prop_get_fdt(Object *obj, Visitor *v, const char *name,
/* shouldn't ever see an FDT_END_NODE before FDT_BEGIN_NODE */
g_assert(fdt_depth > 0);
visit_check_struct(v, &err);
visit_end_struct(v);
visit_end_struct(v, NULL);
if (err) {
error_propagate(errp, err);
return;
@@ -323,7 +323,7 @@ static void prop_get_fdt(Object *obj, Visitor *v, const char *name,
return;
}
}
visit_end_list(v);
visit_end_list(v, NULL);
break;
}
default:
+2 -2
View File
@@ -139,13 +139,13 @@ static void balloon_stats_get_all(Object *obj, Visitor *v, const char *name,
}
visit_check_struct(v, &err);
out_nested:
visit_end_struct(v);
visit_end_struct(v, NULL);
if (!err) {
visit_check_struct(v, &err);
}
out_end:
visit_end_struct(v);
visit_end_struct(v, NULL);
out:
error_propagate(errp, err);
}
+1 -1
View File
@@ -159,7 +159,7 @@ typedef int (*QIOTaskWorker)(QIOTask *task,
* QIOTask *task;
* SocketAddress *addrCopy;
*
* qapi_copy_SocketAddress(&addrCopy, addr);
* addrCopy = QAPI_CLONE(SocketAddress, addr);
* task = qio_task_new(OBJECT(obj), func, opaque, notify);
*
* qio_task_run_in_thread(task, myobject_listen_worker,
+39
View File
@@ -0,0 +1,39 @@
/*
* Clone Visitor
*
* Copyright (C) 2016 Red Hat, Inc.
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*
*/
#ifndef QAPI_CLONE_VISITOR_H
#define QAPI_CLONE_VISITOR_H
#include "qemu/typedefs.h"
#include "qapi/visitor.h"
#include "qapi-visit.h"
/*
* The clone visitor is for direct use only by the QAPI_CLONE() macro;
* it requires that the root visit occur on an object, list, or
* alternate, and is not usable directly on built-in QAPI types.
*/
typedef struct QapiCloneVisitor QapiCloneVisitor;
void *qapi_clone(const void *src, void (*visit_type)(Visitor *, const char *,
void **, Error **));
/*
* Deep-clone QAPI object @src of the given @type, and return the result.
*
* Not usable on QAPI scalars (integers, strings, enums), nor on a
* QAPI object that references the 'any' type. Safe when @src is NULL.
*/
#define QAPI_CLONE(type, src) \
((type *)qapi_clone(src, \
(void (*)(Visitor *, const char *, void**, \
Error **))visit_type_ ## type))
#endif
+1 -4
View File
@@ -23,9 +23,6 @@ typedef struct QapiDeallocVisitor QapiDeallocVisitor;
* qapi_free_FOO() functions, and is the only visitor designed to work
* correctly in the face of a partially-constructed QAPI tree.
*/
QapiDeallocVisitor *qapi_dealloc_visitor_new(void);
void qapi_dealloc_visitor_cleanup(QapiDeallocVisitor *d);
Visitor *qapi_dealloc_get_visitor(QapiDeallocVisitor *v);
Visitor *qapi_dealloc_visitor_new(void);
#endif
+1 -3
View File
@@ -35,8 +35,6 @@ typedef struct OptsVisitor OptsVisitor;
* QTypes. It also requires a non-null list argument to
* visit_start_list().
*/
OptsVisitor *opts_visitor_new(const QemuOpts *opts);
void opts_visitor_cleanup(OptsVisitor *nv);
Visitor *opts_get_visitor(OptsVisitor *nv);
Visitor *opts_visitor_new(const QemuOpts *opts);
#endif
+1 -5
View File
@@ -25,10 +25,6 @@ typedef struct QmpInputVisitor QmpInputVisitor;
* Set @strict to reject a parse that doesn't consume all keys of a
* dictionary; otherwise excess input is ignored.
*/
QmpInputVisitor *qmp_input_visitor_new(QObject *obj, bool strict);
void qmp_input_visitor_cleanup(QmpInputVisitor *v);
Visitor *qmp_input_get_visitor(QmpInputVisitor *v);
Visitor *qmp_input_visitor_new(QObject *obj, bool strict);
#endif
+7 -5
View File
@@ -19,10 +19,12 @@
typedef struct QmpOutputVisitor QmpOutputVisitor;
QmpOutputVisitor *qmp_output_visitor_new(void);
void qmp_output_visitor_cleanup(QmpOutputVisitor *v);
QObject *qmp_output_get_qobject(QmpOutputVisitor *v);
Visitor *qmp_output_get_visitor(QmpOutputVisitor *v);
/*
* Create a new QMP output visitor.
*
* If everything else succeeds, pass @result to visit_complete() to
* collect the result of the visit.
*/
Visitor *qmp_output_visitor_new(QObject **result);
#endif
-1
View File
@@ -20,6 +20,5 @@
#include "qapi/qmp/qstring.h"
#include "qapi/qmp/qdict.h"
#include "qapi/qmp/qlist.h"
#include "qapi/qmp/qjson.h"
#endif /* QEMU_OBJECTS_H */
+1 -4
View File
@@ -22,9 +22,6 @@ typedef struct StringInputVisitor StringInputVisitor;
* QAPI structs, alternates, null, or arbitrary QTypes. It also
* requires a non-null list argument to visit_start_list().
*/
StringInputVisitor *string_input_visitor_new(const char *str);
void string_input_visitor_cleanup(StringInputVisitor *v);
Visitor *string_input_get_visitor(StringInputVisitor *v);
Visitor *string_input_visitor_new(const char *str);
#endif
+9 -5
View File
@@ -18,14 +18,18 @@
typedef struct StringOutputVisitor StringOutputVisitor;
/*
* Create a new string output visitor.
*
* Using @human creates output that is a bit easier for humans to read
* (for example, showing integer values in both decimal and hex).
*
* If everything else succeeds, pass @result to visit_complete() to
* collect the result of the visit.
*
* The string output visitor does not implement support for visiting
* QAPI structs, alternates, null, or arbitrary QTypes. It also
* requires a non-null list argument to visit_start_list().
*/
StringOutputVisitor *string_output_visitor_new(bool human);
void string_output_visitor_cleanup(StringOutputVisitor *v);
char *string_output_get_string(StringOutputVisitor *v);
Visitor *string_output_get_visitor(StringOutputVisitor *v);
Visitor *string_output_visitor_new(bool human, char **result);
#endif
+18 -8
View File
@@ -27,14 +27,18 @@
*/
/*
* There are three classes of visitors; setting the class determines
* There are four classes of visitors; setting the class determines
* how QAPI enums are visited, as well as what additional restrictions
* can be asserted.
* can be asserted. The values are intentionally chosen so as to
* permit some assertions based on whether a given bit is set (that
* is, some assertions apply to input and clone visitors, some
* assertions apply to output and clone visitors).
*/
typedef enum VisitorType {
VISITOR_INPUT,
VISITOR_OUTPUT,
VISITOR_DEALLOC,
VISITOR_INPUT = 1,
VISITOR_OUTPUT = 2,
VISITOR_CLONE = 3,
VISITOR_DEALLOC = 4,
} VisitorType;
struct Visitor
@@ -47,7 +51,7 @@ struct Visitor
void (*check_struct)(Visitor *v, Error **errp);
/* Must be set to visit structs */
void (*end_struct)(Visitor *v);
void (*end_struct)(Visitor *v, void **obj);
/* Must be set; implementations may require @list to be non-null,
* but must document it. */
@@ -58,7 +62,7 @@ struct Visitor
GenericList *(*next_list)(Visitor *v, GenericList *tail, size_t size);
/* Must be set */
void (*end_list)(Visitor *v);
void (*end_list)(Visitor *v, void **list);
/* Must be set by input and dealloc visitors to visit alternates;
* optional for output visitors. */
@@ -67,7 +71,7 @@ struct Visitor
bool promote_int, Error **errp);
/* Optional, needed for dealloc visitor */
void (*end_alternate)(Visitor *v);
void (*end_alternate)(Visitor *v, void **obj);
/* Must be set */
void (*type_int64)(Visitor *v, const char *name, int64_t *obj,
@@ -104,6 +108,12 @@ struct Visitor
/* Must be set */
VisitorType type;
/* Must be set for output visitors, optional otherwise. */
void (*complete)(Visitor *v, void *opaque);
/* Must be set */
void (*free)(Visitor *v);
};
#endif
+109 -52
View File
@@ -24,19 +24,32 @@
* for doing work at each node of a QAPI graph; it can also be used
* for a virtual walk, where there is no actual QAPI C struct.
*
* There are three kinds of visitor classes: input visitors (QMP,
* There are four kinds of visitor classes: input visitors (QMP,
* string, and QemuOpts) parse an external representation and build
* the corresponding QAPI graph, output visitors (QMP and string) take
* a completed QAPI graph and generate an external representation, and
* the dealloc visitor can take a QAPI graph (possibly partially
* constructed) and recursively free its resources. While the dealloc
* and QMP input/output visitors are general, the string and QemuOpts
* visitors have some implementation limitations; see the
* documentation for each visitor for more details on what it
* a completed QAPI graph and generate an external representation, the
* dealloc visitor can take a QAPI graph (possibly partially
* constructed) and recursively free its resources, and the clone
* visitor performs a deep clone of one QAPI object to another. While
* the dealloc and QMP input/output visitors are general, the string,
* QemuOpts, and clone visitors have some implementation limitations;
* see the documentation for each visitor for more details on what it
* supports. Also, see visitor-impl.h for the callback contracts
* implemented by each visitor, and docs/qapi-code-gen.txt for more
* about the QAPI code generator.
*
* All of the visitors are created via:
*
* Visitor *subtype_visitor_new(parameters...);
*
* A visitor should be used for exactly one top-level visit_type_FOO()
* or virtual walk; if that is successful, the caller can optionally
* call visit_complete() (for now, useful only for output visits, but
* safe to call on all visits). Then, regardless of success or
* failure, the user should call visit_free() to clean up resources.
* It is okay to free the visitor without completing the visit, if
* some other error is detected in the meantime.
*
* All QAPI types have a corresponding function with a signature
* roughly compatible with this:
*
@@ -68,9 +81,9 @@
*
* If an error is detected during visit_type_FOO() with an input
* visitor, then *@obj will be NULL for pointer types, and left
* unchanged for scalar types. Using an output visitor with an
* incomplete object has undefined behavior (other than a special case
* for visit_type_str() treating NULL like ""), while the dealloc
* unchanged for scalar types. Using an output or clone visitor with
* an incomplete object has undefined behavior (other than a special
* case for visit_type_str() treating NULL like ""), while the dealloc
* visitor safely handles incomplete objects. Since input visitors
* never produce an incomplete object, such an object is possible only
* by manual construction.
@@ -90,11 +103,19 @@
*
* void qapi_free_FOO(FOO *obj);
*
* which behaves like free() in that @obj may be NULL. Because of
* these functions, the dealloc visitor is seldom used directly
* outside of generated code. QAPI types can also inherit from a base
* class; when this happens, a function is generated for easily going
* from the derived type to the base type:
* where behaves like free() in that @obj may be NULL. Such objects
* may also be used with the following macro, provided alongside the
* clone visitor:
*
* Type *QAPI_CLONE(Type, src);
*
* in order to perform a deep clone of @src. Because of the generated
* qapi_free functions and the QAPI_CLONE() macro, the clone and
* dealloc visitor should not be used directly outside of QAPI code.
*
* QAPI types can also inherit from a base class; when this happens, a
* function is generated for easily going from the derived type to the
* base type:
*
* BASE *qapi_CHILD_base(CHILD *obj);
*
@@ -105,14 +126,14 @@
* Error *err = NULL;
* Visitor *v;
*
* v = ...obtain input visitor...
* v = FOO_visitor_new(...);
* visit_type_Foo(v, NULL, &f, &err);
* if (err) {
* ...handle error...
* } else {
* ...use f...
* }
* ...clean up v...
* visit_free(v);
* qapi_free_Foo(f);
* </example>
*
@@ -122,7 +143,7 @@
* Error *err = NULL;
* Visitor *v;
*
* v = ...obtain input visitor...
* v = FOO_visitor_new(...);
* visit_type_FooList(v, NULL, &l, &err);
* if (err) {
* ...handle error...
@@ -131,7 +152,7 @@
* ...use l->value...
* }
* }
* ...clean up v...
* visit_free(v);
* qapi_free_FooList(l);
* </example>
*
@@ -141,13 +162,17 @@
* Foo *f = ...obtain populated object...
* Error *err = NULL;
* Visitor *v;
* Type *result;
*
* v = ...obtain output visitor...
* v = FOO_visitor_new(..., &result);
* visit_type_Foo(v, NULL, &f, &err);
* if (err) {
* ...handle error...
* } else {
* visit_complete(v, &result);
* ...use result...
* }
* ...clean up v...
* visit_free(v);
* </example>
*
* When visiting a real QAPI struct, this file provides several
@@ -173,7 +198,7 @@
* Error *err = NULL;
* int value;
*
* v = ...obtain visitor...
* v = FOO_visitor_new(...);
* visit_start_struct(v, NULL, NULL, 0, &err);
* if (err) {
* goto out;
@@ -193,15 +218,15 @@
* goto outlist;
* }
* outlist:
* visit_end_list(v);
* visit_end_list(v, NULL);
* if (!err) {
* visit_check_struct(v, &err);
* }
* outobj:
* visit_end_struct(v);
* visit_end_struct(v, NULL);
* out:
* error_propagate(errp, err);
* ...clean up v...
* visit_free(v);
* </example>
*/
@@ -222,6 +247,31 @@ typedef struct GenericAlternate {
char padding[];
} GenericAlternate;
/*** Visitor cleanup ***/
/*
* Complete the visit, collecting any output.
*
* May only be called only once after a successful top-level
* visit_type_FOO() or visit_end_ITEM(), and marks the end of the
* visit. The @opaque pointer should match the output parameter
* passed to the subtype_visitor_new() used to create an output
* visitor, or NULL for any other visitor. Needed for output
* visitors, but may also be called with other visitors.
*/
void visit_complete(Visitor *v, void *opaque);
/*
* Free @v and any resources it has tied up.
*
* May be called whether or not the visit has been successfully
* completed, but should not be called until a top-level
* visit_type_FOO() or visit_start_ITEM() has been performed on the
* visitor. Safe if @v is NULL.
*/
void visit_free(Visitor *v);
/*** Visiting structures ***/
/*
@@ -231,9 +281,9 @@ typedef struct GenericAlternate {
* container; see the general description of @name above.
*
* @obj must be non-NULL for a real walk, in which case @size
* determines how much memory an input visitor will allocate into
* *@obj. @obj may also be NULL for a virtual walk, in which case
* @size is ignored.
* determines how much memory an input or clone visitor will allocate
* into *@obj. @obj may also be NULL for a virtual walk, in which
* case @size is ignored.
*
* @errp obeys typical error usage, and reports failures such as a
* member @name is not present, or present but not an object. On
@@ -242,8 +292,8 @@ typedef struct GenericAlternate {
* After visit_start_struct() succeeds, the caller may visit its
* members one after the other, passing the member's name and address
* within the struct. Finally, visit_end_struct() needs to be called
* to clean up, even if intermediate visits fail. See the examples
* above.
* with the same @obj to clean up, even if intermediate visits fail.
* See the examples above.
*
* FIXME Should this be named visit_start_object, since it is also
* used for QAPI unions, and maps to JSON objects?
@@ -267,12 +317,14 @@ void visit_check_struct(Visitor *v, Error **errp);
/*
* Complete an object visit started earlier.
*
* @obj must match what was passed to the paired visit_start_struct().
*
* 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. Destroying the visitor early
* behaves as if this was implicitly called.
* with visit_free() behaves as if this was implicitly called.
*/
void visit_end_struct(Visitor *v);
void visit_end_struct(Visitor *v, void **obj);
/*** Visiting lists ***/
@@ -284,9 +336,9 @@ void visit_end_struct(Visitor *v);
* container; see the general description of @name above.
*
* @list must be non-NULL for a real walk, in which case @size
* determines how much memory an input visitor will allocate into
* *@list (at least sizeof(GenericList)). Some visitors also allow
* @list to be NULL for a virtual walk, in which case @size is
* determines how much memory an input or clone visitor will allocate
* into *@list (at least sizeof(GenericList)). Some visitors also
* allow @list to be NULL for a virtual walk, in which case @size is
* ignored.
*
* @errp obeys typical error usage, and reports failures such as a
@@ -299,8 +351,9 @@ void visit_end_struct(Visitor *v);
* visit (where @obj is NULL) uses other means. For each list
* element, call the appropriate visit_type_FOO() with name set to
* NULL and obj set to the address of the value member of the list
* element. Finally, visit_end_list() needs to be called to clean up,
* even if intermediate visits fail. See the examples above.
* element. Finally, visit_end_list() needs to be called with the
* same @list to clean up, even if intermediate visits fail. See the
* examples above.
*/
void visit_start_list(Visitor *v, const char *name, GenericList **list,
size_t size, Error **errp);
@@ -324,12 +377,14 @@ GenericList *visit_next_list(Visitor *v, GenericList *tail, size_t size);
/*
* Complete a list visit started earlier.
*
* @list must match what was passed to the paired visit_start_list().
*
* Must be called after any successful use of visit_start_list(), even
* if intermediate processing was skipped due to errors, to allow the
* backend to release any resources. Destroying the visitor early
* behaves as if this was implicitly called.
* with visit_free() behaves as if this was implicitly called.
*/
void visit_end_list(Visitor *v);
void visit_end_list(Visitor *v, void **list);
/*** Visiting alternates ***/
@@ -340,15 +395,16 @@ void visit_end_list(Visitor *v);
* @name expresses the relationship of this alternate to its parent
* container; see the general description of @name above.
*
* @obj must not be NULL. Input visitors use @size to determine how
* much memory to allocate into *@obj, then determine the qtype of the
* next thing to be visited, stored in (*@obj)->type. Other visitors
* will leave @obj unchanged.
* @obj must not be NULL. Input and clone visitors use @size to
* determine how much memory to allocate into *@obj, then determine
* the qtype of the next thing to be visited, stored in (*@obj)->type.
* Other visitors will leave @obj unchanged.
*
* If @promote_int, treat integers as QTYPE_FLOAT.
*
* If successful, this must be paired with visit_end_alternate() to
* clean up, even if visiting the contents of the alternate fails.
* If successful, this must be paired with visit_end_alternate() with
* the same @obj to clean up, even if visiting the contents of the
* alternate fails.
*/
void visit_start_alternate(Visitor *v, const char *name,
GenericAlternate **obj, size_t size,
@@ -357,15 +413,15 @@ void visit_start_alternate(Visitor *v, const char *name,
/*
* Finish visiting an alternate type.
*
* @obj must match what was passed to the paired visit_start_alternate().
*
* Must be called after any successful use of visit_start_alternate(),
* even if intermediate processing was skipped due to errors, to allow
* the backend to release any resources. Destroying the visitor early
* behaves as if this was implicitly called.
* with visit_free() behaves as if this was implicitly called.
*
* TODO: Should all the visit_end_* interfaces take obj parameter, so
* that dealloc visitor need not track what was passed in visit_start?
*/
void visit_end_alternate(Visitor *v);
void visit_end_alternate(Visitor *v, void **obj);
/*** Other helpers ***/
@@ -507,9 +563,10 @@ void visit_type_bool(Visitor *v, const char *name, bool *obj, Error **errp);
* @name expresses the relationship of this string to its parent
* container; see the general description of @name above.
*
* @obj must be non-NULL. Input visitors set *@obj to the value
* (never NULL). Other visitors leave *@obj unchanged, and commonly
* treat NULL like "".
* @obj must be non-NULL. Input and clone visitors set *@obj to the
* value (always using "" rather than NULL for an empty string).
* Other visitors leave *@obj unchanged, and commonly treat NULL like
* "".
*
* It is safe to cast away const when preparing a (const char *) value
* into @obj for use by an output visitor.

Some files were not shown because too many files have changed in this diff Show More