block: fix deadlock in bdrv_co_flush
[qemu/kevin.git] / qapi / qmp-input-visitor.c
blob64dd392e6f7a1999fb39de488c12ded5539d9e9b
1 /*
2 * Input Visitor
4 * Copyright (C) 2012-2016 Red Hat, Inc.
5 * Copyright IBM, Corp. 2011
7 * Authors:
8 * Anthony Liguori <aliguori@us.ibm.com>
10 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
11 * See the COPYING.LIB file in the top-level directory.
15 #include "qemu/osdep.h"
16 #include "qapi/error.h"
17 #include "qapi/qmp-input-visitor.h"
18 #include "qapi/visitor-impl.h"
19 #include "qemu/queue.h"
20 #include "qemu-common.h"
21 #include "qapi/qmp/types.h"
22 #include "qapi/qmp/qerror.h"
24 #define QIV_STACK_SIZE 1024
26 typedef struct StackObject
28 QObject *obj; /* Object being visited */
29 void *qapi; /* sanity check that caller uses same pointer */
31 GHashTable *h; /* If obj is dict: unvisited keys */
32 const QListEntry *entry; /* If obj is list: unvisited tail */
34 QSLIST_ENTRY(StackObject) node;
35 } StackObject;
37 struct QmpInputVisitor
39 Visitor visitor;
41 /* Root of visit at visitor creation. */
42 QObject *root;
44 /* Stack of objects being visited (all entries will be either
45 * QDict or QList). */
46 QSLIST_HEAD(, StackObject) stack;
48 /* True to reject parse in visit_end_struct() if unvisited keys remain. */
49 bool strict;
52 static QmpInputVisitor *to_qiv(Visitor *v)
54 return container_of(v, QmpInputVisitor, visitor);
57 static QObject *qmp_input_get_object(QmpInputVisitor *qiv,
58 const char *name,
59 bool consume)
61 StackObject *tos;
62 QObject *qobj;
63 QObject *ret;
65 if (QSLIST_EMPTY(&qiv->stack)) {
66 /* Starting at root, name is ignored. */
67 return qiv->root;
70 /* We are in a container; find the next element. */
71 tos = QSLIST_FIRST(&qiv->stack);
72 qobj = tos->obj;
73 assert(qobj);
75 if (qobject_type(qobj) == QTYPE_QDICT) {
76 assert(name);
77 ret = qdict_get(qobject_to_qdict(qobj), name);
78 if (tos->h && consume && ret) {
79 bool removed = g_hash_table_remove(tos->h, name);
80 assert(removed);
82 } else {
83 assert(qobject_type(qobj) == QTYPE_QLIST);
84 assert(!name);
85 ret = qlist_entry_obj(tos->entry);
86 if (consume) {
87 tos->entry = qlist_next(tos->entry);
91 return ret;
94 static void qdict_add_key(const char *key, QObject *obj, void *opaque)
96 GHashTable *h = opaque;
97 g_hash_table_insert(h, (gpointer) key, NULL);
100 static const QListEntry *qmp_input_push(QmpInputVisitor *qiv, QObject *obj,
101 void *qapi, Error **errp)
103 GHashTable *h;
104 StackObject *tos = g_new0(StackObject, 1);
106 assert(obj);
107 tos->obj = obj;
108 tos->qapi = qapi;
110 if (qiv->strict && qobject_type(obj) == QTYPE_QDICT) {
111 h = g_hash_table_new(g_str_hash, g_str_equal);
112 qdict_iter(qobject_to_qdict(obj), qdict_add_key, h);
113 tos->h = h;
114 } else if (qobject_type(obj) == QTYPE_QLIST) {
115 tos->entry = qlist_first(qobject_to_qlist(obj));
118 QSLIST_INSERT_HEAD(&qiv->stack, tos, node);
119 return tos->entry;
123 static void qmp_input_check_struct(Visitor *v, Error **errp)
125 QmpInputVisitor *qiv = to_qiv(v);
126 StackObject *tos = QSLIST_FIRST(&qiv->stack);
128 assert(tos && !tos->entry);
129 if (qiv->strict) {
130 GHashTable *const top_ht = tos->h;
131 if (top_ht) {
132 GHashTableIter iter;
133 const char *key;
135 g_hash_table_iter_init(&iter, top_ht);
136 if (g_hash_table_iter_next(&iter, (void **)&key, NULL)) {
137 error_setg(errp, QERR_QMP_EXTRA_MEMBER, key);
143 static void qmp_input_stack_object_free(StackObject *tos)
145 if (tos->h) {
146 g_hash_table_unref(tos->h);
149 g_free(tos);
152 static void qmp_input_pop(Visitor *v, void **obj)
154 QmpInputVisitor *qiv = to_qiv(v);
155 StackObject *tos = QSLIST_FIRST(&qiv->stack);
157 assert(tos && tos->qapi == obj);
158 QSLIST_REMOVE_HEAD(&qiv->stack, node);
159 qmp_input_stack_object_free(tos);
162 static void qmp_input_start_struct(Visitor *v, const char *name, void **obj,
163 size_t size, Error **errp)
165 QmpInputVisitor *qiv = to_qiv(v);
166 QObject *qobj = qmp_input_get_object(qiv, name, true);
167 Error *err = NULL;
169 if (obj) {
170 *obj = NULL;
172 if (!qobj || qobject_type(qobj) != QTYPE_QDICT) {
173 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
174 "QDict");
175 return;
178 qmp_input_push(qiv, qobj, obj, &err);
179 if (err) {
180 error_propagate(errp, err);
181 return;
184 if (obj) {
185 *obj = g_malloc0(size);
190 static void qmp_input_start_list(Visitor *v, const char *name,
191 GenericList **list, size_t size, Error **errp)
193 QmpInputVisitor *qiv = to_qiv(v);
194 QObject *qobj = qmp_input_get_object(qiv, name, true);
195 const QListEntry *entry;
197 if (!qobj || qobject_type(qobj) != QTYPE_QLIST) {
198 if (list) {
199 *list = NULL;
201 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
202 "list");
203 return;
206 entry = qmp_input_push(qiv, qobj, list, errp);
207 if (list) {
208 if (entry) {
209 *list = g_malloc0(size);
210 } else {
211 *list = NULL;
216 static GenericList *qmp_input_next_list(Visitor *v, GenericList *tail,
217 size_t size)
219 QmpInputVisitor *qiv = to_qiv(v);
220 StackObject *so = QSLIST_FIRST(&qiv->stack);
222 if (!so->entry) {
223 return NULL;
225 tail->next = g_malloc0(size);
226 return tail->next;
230 static void qmp_input_start_alternate(Visitor *v, const char *name,
231 GenericAlternate **obj, size_t size,
232 bool promote_int, Error **errp)
234 QmpInputVisitor *qiv = to_qiv(v);
235 QObject *qobj = qmp_input_get_object(qiv, name, false);
237 if (!qobj) {
238 *obj = NULL;
239 error_setg(errp, QERR_MISSING_PARAMETER, name ? name : "null");
240 return;
242 *obj = g_malloc0(size);
243 (*obj)->type = qobject_type(qobj);
244 if (promote_int && (*obj)->type == QTYPE_QINT) {
245 (*obj)->type = QTYPE_QFLOAT;
249 static void qmp_input_type_int64(Visitor *v, const char *name, int64_t *obj,
250 Error **errp)
252 QmpInputVisitor *qiv = to_qiv(v);
253 QInt *qint = qobject_to_qint(qmp_input_get_object(qiv, name, true));
255 if (!qint) {
256 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
257 "integer");
258 return;
261 *obj = qint_get_int(qint);
264 static void qmp_input_type_uint64(Visitor *v, const char *name, uint64_t *obj,
265 Error **errp)
267 /* FIXME: qobject_to_qint mishandles values over INT64_MAX */
268 QmpInputVisitor *qiv = to_qiv(v);
269 QInt *qint = qobject_to_qint(qmp_input_get_object(qiv, name, true));
271 if (!qint) {
272 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
273 "integer");
274 return;
277 *obj = qint_get_int(qint);
280 static void qmp_input_type_bool(Visitor *v, const char *name, bool *obj,
281 Error **errp)
283 QmpInputVisitor *qiv = to_qiv(v);
284 QBool *qbool = qobject_to_qbool(qmp_input_get_object(qiv, name, true));
286 if (!qbool) {
287 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
288 "boolean");
289 return;
292 *obj = qbool_get_bool(qbool);
295 static void qmp_input_type_str(Visitor *v, const char *name, char **obj,
296 Error **errp)
298 QmpInputVisitor *qiv = to_qiv(v);
299 QString *qstr = qobject_to_qstring(qmp_input_get_object(qiv, name, true));
301 if (!qstr) {
302 *obj = NULL;
303 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
304 "string");
305 return;
308 *obj = g_strdup(qstring_get_str(qstr));
311 static void qmp_input_type_number(Visitor *v, const char *name, double *obj,
312 Error **errp)
314 QmpInputVisitor *qiv = to_qiv(v);
315 QObject *qobj = qmp_input_get_object(qiv, name, true);
316 QInt *qint;
317 QFloat *qfloat;
319 qint = qobject_to_qint(qobj);
320 if (qint) {
321 *obj = qint_get_int(qobject_to_qint(qobj));
322 return;
325 qfloat = qobject_to_qfloat(qobj);
326 if (qfloat) {
327 *obj = qfloat_get_double(qobject_to_qfloat(qobj));
328 return;
331 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
332 "number");
335 static void qmp_input_type_any(Visitor *v, const char *name, QObject **obj,
336 Error **errp)
338 QmpInputVisitor *qiv = to_qiv(v);
339 QObject *qobj = qmp_input_get_object(qiv, name, true);
341 qobject_incref(qobj);
342 *obj = qobj;
345 static void qmp_input_type_null(Visitor *v, const char *name, Error **errp)
347 QmpInputVisitor *qiv = to_qiv(v);
348 QObject *qobj = qmp_input_get_object(qiv, name, true);
350 if (qobject_type(qobj) != QTYPE_QNULL) {
351 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
352 "null");
356 static void qmp_input_optional(Visitor *v, const char *name, bool *present)
358 QmpInputVisitor *qiv = to_qiv(v);
359 QObject *qobj = qmp_input_get_object(qiv, name, false);
361 if (!qobj) {
362 *present = false;
363 return;
366 *present = true;
369 static void qmp_input_free(Visitor *v)
371 QmpInputVisitor *qiv = to_qiv(v);
372 while (!QSLIST_EMPTY(&qiv->stack)) {
373 StackObject *tos = QSLIST_FIRST(&qiv->stack);
375 QSLIST_REMOVE_HEAD(&qiv->stack, node);
376 qmp_input_stack_object_free(tos);
379 qobject_decref(qiv->root);
380 g_free(qiv);
383 Visitor *qmp_input_visitor_new(QObject *obj, bool strict)
385 QmpInputVisitor *v;
387 v = g_malloc0(sizeof(*v));
389 v->visitor.type = VISITOR_INPUT;
390 v->visitor.start_struct = qmp_input_start_struct;
391 v->visitor.check_struct = qmp_input_check_struct;
392 v->visitor.end_struct = qmp_input_pop;
393 v->visitor.start_list = qmp_input_start_list;
394 v->visitor.next_list = qmp_input_next_list;
395 v->visitor.end_list = qmp_input_pop;
396 v->visitor.start_alternate = qmp_input_start_alternate;
397 v->visitor.type_int64 = qmp_input_type_int64;
398 v->visitor.type_uint64 = qmp_input_type_uint64;
399 v->visitor.type_bool = qmp_input_type_bool;
400 v->visitor.type_str = qmp_input_type_str;
401 v->visitor.type_number = qmp_input_type_number;
402 v->visitor.type_any = qmp_input_type_any;
403 v->visitor.type_null = qmp_input_type_null;
404 v->visitor.optional = qmp_input_optional;
405 v->visitor.free = qmp_input_free;
406 v->strict = strict;
408 v->root = obj;
409 qobject_incref(obj);
411 return &v->visitor;