mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
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:
+14
-16
@@ -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
@@ -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
@@ -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
@@ -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)
|
||||
|
||||
@@ -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
@@ -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) {
|
||||
|
||||
@@ -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
@@ -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:
|
||||
|
||||
@@ -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
@@ -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,
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
Reference in New Issue
Block a user